@vertaaux/cli 0.4.0 → 0.5.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 (248) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/MIGRATION.md +239 -0
  3. package/README.md +62 -17
  4. package/dist/app/interactive-app.d.ts +103 -0
  5. package/dist/app/interactive-app.d.ts.map +1 -0
  6. package/dist/app/interactive-app.js +328 -0
  7. package/dist/app/layout/canvas.d.ts +23 -0
  8. package/dist/app/layout/canvas.d.ts.map +1 -0
  9. package/dist/app/layout/canvas.js +36 -0
  10. package/dist/app/layout/footer.d.ts +31 -0
  11. package/dist/app/layout/footer.d.ts.map +1 -0
  12. package/dist/app/layout/footer.js +41 -0
  13. package/dist/app/layout/header.d.ts +20 -0
  14. package/dist/app/layout/header.d.ts.map +1 -0
  15. package/dist/app/layout/header.js +27 -0
  16. package/dist/app/menu/categories.d.ts +20 -0
  17. package/dist/app/menu/categories.d.ts.map +1 -0
  18. package/dist/app/menu/categories.js +166 -0
  19. package/dist/app/menu/filter.d.ts +17 -0
  20. package/dist/app/menu/filter.d.ts.map +1 -0
  21. package/dist/app/menu/filter.js +33 -0
  22. package/dist/app/menu/menu-view.d.ts +35 -0
  23. package/dist/app/menu/menu-view.d.ts.map +1 -0
  24. package/dist/app/menu/menu-view.js +230 -0
  25. package/dist/app/menu/recent.d.ts +24 -0
  26. package/dist/app/menu/recent.d.ts.map +1 -0
  27. package/dist/app/menu/recent.js +49 -0
  28. package/dist/app/types.d.ts +43 -0
  29. package/dist/app/types.d.ts.map +1 -0
  30. package/dist/app/types.js +7 -0
  31. package/dist/app/views/command-runner.d.ts +36 -0
  32. package/dist/app/views/command-runner.d.ts.map +1 -0
  33. package/dist/app/views/command-runner.js +415 -0
  34. package/dist/app/views/help-overlay.d.ts +21 -0
  35. package/dist/app/views/help-overlay.d.ts.map +1 -0
  36. package/dist/app/views/help-overlay.js +46 -0
  37. package/dist/auth/ci-token.d.ts +8 -2
  38. package/dist/auth/ci-token.d.ts.map +1 -1
  39. package/dist/auth/ci-token.js +15 -30
  40. package/dist/auth/device-flow.d.ts +2 -1
  41. package/dist/auth/device-flow.d.ts.map +1 -1
  42. package/dist/auth/device-flow.js +13 -10
  43. package/dist/auth/token-store.d.ts.map +1 -1
  44. package/dist/auth/token-store.js +12 -2
  45. package/dist/baseline/diff.d.ts +2 -2
  46. package/dist/baseline/diff.d.ts.map +1 -1
  47. package/dist/baseline/diff.js +15 -34
  48. package/dist/commands/a11y.d.ts +11 -0
  49. package/dist/commands/a11y.d.ts.map +1 -0
  50. package/dist/commands/a11y.js +149 -0
  51. package/dist/commands/audit/artifacts.d.ts +27 -0
  52. package/dist/commands/audit/artifacts.d.ts.map +1 -0
  53. package/dist/commands/audit/artifacts.js +158 -0
  54. package/dist/commands/audit/ci-detection.d.ts +18 -0
  55. package/dist/commands/audit/ci-detection.d.ts.map +1 -0
  56. package/dist/commands/audit/ci-detection.js +71 -0
  57. package/dist/commands/audit/explain.d.ts +11 -0
  58. package/dist/commands/audit/explain.d.ts.map +1 -0
  59. package/dist/commands/audit/explain.js +45 -0
  60. package/dist/commands/audit/filters.d.ts +17 -0
  61. package/dist/commands/audit/filters.d.ts.map +1 -0
  62. package/dist/commands/audit/filters.js +40 -0
  63. package/dist/commands/audit/index.d.ts +18 -0
  64. package/dist/commands/audit/index.d.ts.map +1 -0
  65. package/dist/commands/audit/index.js +589 -0
  66. package/dist/commands/audit/output.d.ts +32 -0
  67. package/dist/commands/audit/output.d.ts.map +1 -0
  68. package/dist/commands/audit/output.js +129 -0
  69. package/dist/commands/audit/policy.d.ts +27 -0
  70. package/dist/commands/audit/policy.d.ts.map +1 -0
  71. package/dist/commands/audit/policy.js +147 -0
  72. package/dist/commands/audit/scoring.d.ts +23 -0
  73. package/dist/commands/audit/scoring.d.ts.map +1 -0
  74. package/dist/commands/audit/scoring.js +70 -0
  75. package/dist/commands/audit/types.d.ts +89 -0
  76. package/dist/commands/audit/types.d.ts.map +1 -0
  77. package/dist/commands/audit/types.js +8 -0
  78. package/dist/commands/audit.d.ts +2 -60
  79. package/dist/commands/audit.d.ts.map +1 -1
  80. package/dist/commands/audit.js +2 -1097
  81. package/dist/commands/baseline.d.ts +2 -0
  82. package/dist/commands/baseline.d.ts.map +1 -1
  83. package/dist/commands/baseline.js +221 -123
  84. package/dist/commands/comment.d.ts +22 -0
  85. package/dist/commands/comment.d.ts.map +1 -1
  86. package/dist/commands/comment.js +127 -62
  87. package/dist/commands/compare.d.ts +17 -0
  88. package/dist/commands/compare.d.ts.map +1 -1
  89. package/dist/commands/compare.js +288 -181
  90. package/dist/commands/diff.d.ts +7 -0
  91. package/dist/commands/diff.d.ts.map +1 -1
  92. package/dist/commands/diff.js +181 -143
  93. package/dist/commands/doc.d.ts +10 -0
  94. package/dist/commands/doc.d.ts.map +1 -1
  95. package/dist/commands/doc.js +135 -77
  96. package/dist/commands/doctor.d.ts +2 -0
  97. package/dist/commands/doctor.d.ts.map +1 -1
  98. package/dist/commands/doctor.js +166 -19
  99. package/dist/commands/download.d.ts +10 -0
  100. package/dist/commands/download.d.ts.map +1 -1
  101. package/dist/commands/download.js +169 -112
  102. package/dist/commands/explain.d.ts +5 -0
  103. package/dist/commands/explain.d.ts.map +1 -1
  104. package/dist/commands/explain.js +242 -156
  105. package/dist/commands/fix-all.d.ts +25 -0
  106. package/dist/commands/fix-all.d.ts.map +1 -0
  107. package/dist/commands/fix-all.js +206 -0
  108. package/dist/commands/fix-plan.d.ts +9 -0
  109. package/dist/commands/fix-plan.d.ts.map +1 -1
  110. package/dist/commands/fix-plan.js +154 -90
  111. package/dist/commands/fix.d.ts +17 -0
  112. package/dist/commands/fix.d.ts.map +1 -0
  113. package/dist/commands/fix.js +111 -0
  114. package/dist/commands/init.d.ts +11 -0
  115. package/dist/commands/init.d.ts.map +1 -1
  116. package/dist/commands/init.js +94 -42
  117. package/dist/commands/login.d.ts +18 -0
  118. package/dist/commands/login.d.ts.map +1 -1
  119. package/dist/commands/login.js +263 -92
  120. package/dist/commands/patch-review.d.ts +11 -0
  121. package/dist/commands/patch-review.d.ts.map +1 -1
  122. package/dist/commands/patch-review.js +160 -98
  123. package/dist/commands/policy.d.ts +31 -0
  124. package/dist/commands/policy.d.ts.map +1 -1
  125. package/dist/commands/policy.js +270 -125
  126. package/dist/commands/release-notes.d.ts +10 -0
  127. package/dist/commands/release-notes.d.ts.map +1 -1
  128. package/dist/commands/release-notes.js +128 -74
  129. package/dist/commands/scan.d.ts +13 -0
  130. package/dist/commands/scan.d.ts.map +1 -0
  131. package/dist/commands/scan.js +133 -0
  132. package/dist/commands/status.d.ts +9 -0
  133. package/dist/commands/status.d.ts.map +1 -0
  134. package/dist/commands/status.js +81 -0
  135. package/dist/commands/suggest.d.ts +10 -0
  136. package/dist/commands/suggest.d.ts.map +1 -1
  137. package/dist/commands/suggest.js +180 -83
  138. package/dist/commands/triage.d.ts +35 -0
  139. package/dist/commands/triage.d.ts.map +1 -1
  140. package/dist/commands/triage.js +207 -82
  141. package/dist/commands/upload.d.ts +9 -0
  142. package/dist/commands/upload.d.ts.map +1 -1
  143. package/dist/commands/upload.js +140 -101
  144. package/dist/commands/verify.d.ts +13 -0
  145. package/dist/commands/verify.d.ts.map +1 -0
  146. package/dist/commands/verify.js +118 -0
  147. package/dist/config/schema.d.ts +4 -0
  148. package/dist/config/schema.d.ts.map +1 -1
  149. package/dist/index.d.ts +3 -2
  150. package/dist/index.d.ts.map +1 -1
  151. package/dist/index.js +127 -991
  152. package/dist/interactive/fix-wizard.d.ts +3 -0
  153. package/dist/interactive/fix-wizard.d.ts.map +1 -1
  154. package/dist/interactive/fix-wizard.js +130 -112
  155. package/dist/interactive/init-wizard.d.ts +3 -1
  156. package/dist/interactive/init-wizard.d.ts.map +1 -1
  157. package/dist/interactive/init-wizard.js +207 -138
  158. package/dist/interactive/prompts.d.ts +7 -3
  159. package/dist/interactive/prompts.d.ts.map +1 -1
  160. package/dist/interactive/prompts.js +44 -23
  161. package/dist/output/envelope.d.ts +9 -0
  162. package/dist/output/envelope.d.ts.map +1 -1
  163. package/dist/output/envelope.js +37 -3
  164. package/dist/output/factory.d.ts +2 -1
  165. package/dist/output/factory.d.ts.map +1 -1
  166. package/dist/output/html.d.ts +2 -1
  167. package/dist/output/html.d.ts.map +1 -1
  168. package/dist/output/html.js +3 -2
  169. package/dist/output/human.d.ts +2 -1
  170. package/dist/output/human.d.ts.map +1 -1
  171. package/dist/output/human.js +3 -2
  172. package/dist/output/json.d.ts +2 -1
  173. package/dist/output/json.d.ts.map +1 -1
  174. package/dist/output/junit.d.ts +2 -1
  175. package/dist/output/junit.d.ts.map +1 -1
  176. package/dist/output/sarif.d.ts +2 -1
  177. package/dist/output/sarif.d.ts.map +1 -1
  178. package/dist/policy/schema.d.ts +137 -0
  179. package/dist/policy/schema.d.ts.map +1 -1
  180. package/dist/policy/schema.js +107 -0
  181. package/dist/prompts/command-catalog.js +9 -9
  182. package/dist/types.d.ts +74 -0
  183. package/dist/types.d.ts.map +1 -0
  184. package/dist/types.js +5 -0
  185. package/dist/ui/banner.d.ts +34 -0
  186. package/dist/ui/banner.d.ts.map +1 -1
  187. package/dist/ui/banner.js +97 -5
  188. package/dist/ui/diagnostics.d.ts +9 -4
  189. package/dist/ui/diagnostics.d.ts.map +1 -1
  190. package/dist/ui/diagnostics.js +32 -82
  191. package/dist/ui/strings.d.ts +373 -0
  192. package/dist/ui/strings.d.ts.map +1 -0
  193. package/dist/ui/strings.js +499 -0
  194. package/dist/ui/table.d.ts +0 -2
  195. package/dist/ui/table.d.ts.map +1 -1
  196. package/dist/ui/table.js +3 -4
  197. package/dist/utils/api-client.d.ts +46 -0
  198. package/dist/utils/api-client.d.ts.map +1 -0
  199. package/dist/utils/api-client.js +170 -0
  200. package/dist/utils/client.d.ts +29 -18
  201. package/dist/utils/client.d.ts.map +1 -1
  202. package/dist/utils/client.js +104 -12
  203. package/dist/utils/formatters.d.ts +38 -0
  204. package/dist/utils/formatters.d.ts.map +1 -0
  205. package/dist/utils/formatters.js +277 -0
  206. package/dist/utils/root-args.d.ts +12 -0
  207. package/dist/utils/root-args.d.ts.map +1 -0
  208. package/dist/utils/root-args.js +44 -0
  209. package/dist/utils/stdin.d.ts +7 -0
  210. package/dist/utils/stdin.d.ts.map +1 -1
  211. package/dist/utils/stdin.js +32 -2
  212. package/dist/utils/url-classify.d.ts.map +1 -1
  213. package/dist/utils/url-classify.js +24 -3
  214. package/node_modules/@vertaaux/tui/dist/index.cjs +1216 -27
  215. package/node_modules/@vertaaux/tui/dist/index.cjs.map +1 -1
  216. package/node_modules/@vertaaux/tui/dist/index.d.cts +361 -4
  217. package/node_modules/@vertaaux/tui/dist/index.d.ts +361 -4
  218. package/node_modules/@vertaaux/tui/dist/index.js +1189 -27
  219. package/node_modules/@vertaaux/tui/dist/index.js.map +1 -1
  220. package/node_modules/@vertaaux/tui/package.json +2 -3
  221. package/node_modules/chalk/license +9 -0
  222. package/node_modules/chalk/package.json +83 -0
  223. package/node_modules/chalk/readme.md +297 -0
  224. package/node_modules/chalk/source/index.d.ts +325 -0
  225. package/node_modules/chalk/source/index.js +225 -0
  226. package/node_modules/chalk/source/utilities.js +33 -0
  227. package/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
  228. package/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
  229. package/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
  230. package/node_modules/chalk/source/vendor/supports-color/browser.js +34 -0
  231. package/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
  232. package/node_modules/chalk/source/vendor/supports-color/index.js +190 -0
  233. package/package.json +20 -5
  234. package/dist/commands/client.d.ts +0 -14
  235. package/dist/commands/client.d.ts.map +0 -1
  236. package/dist/commands/client.js +0 -362
  237. package/dist/commands/drift.d.ts +0 -15
  238. package/dist/commands/drift.d.ts.map +0 -1
  239. package/dist/commands/drift.js +0 -309
  240. package/dist/commands/protect.d.ts +0 -16
  241. package/dist/commands/protect.d.ts.map +0 -1
  242. package/dist/commands/protect.js +0 -323
  243. package/dist/commands/report.d.ts +0 -15
  244. package/dist/commands/report.d.ts.map +0 -1
  245. package/dist/commands/report.js +0 -214
  246. package/dist/policy/sync.d.ts +0 -67
  247. package/dist/policy/sync.d.ts.map +0 -1
  248. package/dist/policy/sync.js +0 -147
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Output formatting utilities for the VertaaUX CLI legacy commands.
3
+ * Provides markdown and JSON formatting functions for audit/fix/verify results.
4
+ */
5
+ import { scoreColor, boldColor } from "@vertaaux/tui";
6
+ import { writeOutput } from "../output/envelope.js";
7
+ // ============================================================================
8
+ // Data normalization
9
+ // ============================================================================
10
+ export function normalizeIssues(issues) {
11
+ if (Array.isArray(issues))
12
+ return issues;
13
+ if (issues && typeof issues === "object") {
14
+ const values = Object.values(issues);
15
+ return values.flatMap((value) => (Array.isArray(value) ? value : []));
16
+ }
17
+ return [];
18
+ }
19
+ export function toNumber(value) {
20
+ if (typeof value === "number" && Number.isFinite(value))
21
+ return value;
22
+ return null;
23
+ }
24
+ export function getOverallScore(scores) {
25
+ if (!scores)
26
+ return null;
27
+ const s = scores;
28
+ const direct = toNumber(s.overall ?? s.ux ?? s.total);
29
+ if (direct !== null)
30
+ return direct;
31
+ const numeric = Object.values(s)
32
+ .map((value) => toNumber(value))
33
+ .filter((value) => value !== null);
34
+ if (numeric.length === 0)
35
+ return null;
36
+ const avg = numeric.reduce((sum, value) => sum + value, 0) / numeric.length;
37
+ return Math.round(avg);
38
+ }
39
+ export function getCategoryScore(scores, key) {
40
+ if (!scores)
41
+ return null;
42
+ return toNumber(scores[key]);
43
+ }
44
+ // ============================================================================
45
+ // Markdown formatters
46
+ // ============================================================================
47
+ export function formatScoresTable(scores) {
48
+ if (!scores)
49
+ return "No scores available.";
50
+ const entries = Object.entries(scores).filter(([, value]) => typeof value === "number");
51
+ if (entries.length === 0)
52
+ return "No scores available.";
53
+ const lines = ["| Category | Score |", "| --- | --- |"];
54
+ for (const [key, value] of entries) {
55
+ lines.push(`| ${key} | ${value} |`);
56
+ }
57
+ return lines.join("\n");
58
+ }
59
+ export function formatIssuesList(issues, limit = 5) {
60
+ if (!issues.length)
61
+ return "No issues.";
62
+ const lines = issues.slice(0, limit).map((issue, index) => {
63
+ const label = issue.title || issue.id || "Issue";
64
+ const severity = issue.severity ? issue.severity.toUpperCase() : "INFO";
65
+ return `${index + 1}. [${severity}] ${label}`;
66
+ });
67
+ if (issues.length > limit) {
68
+ lines.push(`...and ${issues.length - limit} more`);
69
+ }
70
+ return lines.join("\n");
71
+ }
72
+ export function formatAuditMarkdown(result) {
73
+ const status = result.status || "unknown";
74
+ const lines = [`## Audit Results`, `- Status: ${status}`];
75
+ if (result.job_id)
76
+ lines.push(`- Job ID: ${result.job_id}`);
77
+ if (result.url)
78
+ lines.push(`- URL: ${result.url}`);
79
+ if (result.mode)
80
+ lines.push(`- Mode: ${result.mode}`);
81
+ if (typeof result.progress === "number" && status !== "completed") {
82
+ lines.push(`- Progress: ${result.progress}%`);
83
+ }
84
+ if (status !== "completed")
85
+ return lines.join("\n");
86
+ const overall = getOverallScore(result.scores);
87
+ if (overall !== null)
88
+ lines.push(`- Overall score: ${boldColor(String(overall), scoreColor(overall))}`);
89
+ lines.push("\n### Scores");
90
+ lines.push(formatScoresTable(result.scores));
91
+ const issues = normalizeIssues(result.issues);
92
+ lines.push("\n### Issues");
93
+ lines.push(`Total issues: ${issues.length}`);
94
+ lines.push(formatIssuesList(issues));
95
+ return lines.join("\n");
96
+ }
97
+ export function formatA11yMarkdown(result) {
98
+ const lines = [`## Accessibility Audit`, `- Status: ${result.status || "unknown"}`];
99
+ if (result.url)
100
+ lines.push(`- URL: ${result.url}`);
101
+ if (result.mode)
102
+ lines.push(`- Mode: ${result.mode}`);
103
+ if (result.status !== "completed")
104
+ return lines.join("\n");
105
+ const a11yScore = getCategoryScore(result.scores, "accessibility");
106
+ if (a11yScore !== null)
107
+ lines.push(`- Accessibility score: ${boldColor(String(a11yScore), scoreColor(a11yScore))}`);
108
+ const issues = normalizeIssues(result.issues).filter((issue) => {
109
+ const category = (issue.category || "").toLowerCase();
110
+ return (category.includes("accessibility") ||
111
+ category.includes("a11y") ||
112
+ category.includes("wcag"));
113
+ });
114
+ lines.push("\n### Accessibility Issues");
115
+ lines.push(`Total accessibility issues: ${issues.length}`);
116
+ lines.push(formatIssuesList(issues));
117
+ return lines.join("\n");
118
+ }
119
+ export function formatCompareMarkdown(compare) {
120
+ const lines = ["## Audit Comparison"];
121
+ lines.push(`- URL A: ${compare.urlA}`);
122
+ lines.push(`- URL B: ${compare.urlB}`);
123
+ lines.push(`- Job A: ${compare.jobA}`);
124
+ lines.push(`- Job B: ${compare.jobB}`);
125
+ lines.push("\n### Overall Scores");
126
+ lines.push("| Site | Score | Delta |");
127
+ lines.push("| --- | --- | --- |");
128
+ lines.push(`| A | ${compare.overallA !== null ? boldColor(String(compare.overallA), scoreColor(compare.overallA)) : "n/a"} | ${compare.delta ?? "n/a"} |`);
129
+ lines.push(`| B | ${compare.overallB !== null ? boldColor(String(compare.overallB), scoreColor(compare.overallB)) : "n/a"} | ${compare.delta ?? "n/a"} |`);
130
+ lines.push("\n### Category Scores");
131
+ lines.push("| Category | A | B | Delta |");
132
+ lines.push("| --- | --- | --- | --- |");
133
+ for (const [key, values] of Object.entries(compare.categoryDeltas)) {
134
+ lines.push(`| ${key} | ${values.a ?? "n/a"} | ${values.b ?? "n/a"} | ${values.delta ?? "n/a"} |`);
135
+ }
136
+ lines.push("\n### Issue Counts");
137
+ lines.push(`- A: ${compare.issuesA}`);
138
+ lines.push(`- B: ${compare.issuesB}`);
139
+ return lines.join("\n");
140
+ }
141
+ export function formatExplainMarkdown(issue) {
142
+ const lines = ["## Issue Explanation"];
143
+ if (issue.id)
144
+ lines.push(`- ID: ${issue.id}`);
145
+ if (issue.severity)
146
+ lines.push(`- Severity: ${issue.severity}`);
147
+ if (issue.category)
148
+ lines.push(`- Category: ${issue.category}`);
149
+ if (issue.selector)
150
+ lines.push(`- Selector: ${issue.selector}`);
151
+ if (issue.description) {
152
+ lines.push("\n### Description");
153
+ lines.push(issue.description);
154
+ }
155
+ const recommendation = issue.recommendation || issue.recommended_fix;
156
+ if (recommendation) {
157
+ lines.push("\n### Recommendation");
158
+ lines.push(recommendation);
159
+ }
160
+ if (issue.wcag_reference) {
161
+ lines.push("\n### WCAG Reference");
162
+ lines.push(issue.wcag_reference);
163
+ }
164
+ return lines.join("\n");
165
+ }
166
+ export function formatPatchMarkdown(patch) {
167
+ if (!patch)
168
+ return "No patch generated.";
169
+ const lines = [
170
+ "## Patch Generated",
171
+ "",
172
+ `**Confidence:** ${patch.confidence.label} (${patch.confidence.percentage}%)`,
173
+ `**Classification:** ${patch.classification}`,
174
+ "",
175
+ "### Explanation",
176
+ patch.explanation,
177
+ "",
178
+ "### Search",
179
+ "```",
180
+ patch.search,
181
+ "```",
182
+ "",
183
+ "### Replace",
184
+ "```",
185
+ patch.replace,
186
+ "```",
187
+ ];
188
+ return lines.join("\n");
189
+ }
190
+ export function formatVerifyMarkdown(result) {
191
+ if (!result.success || !result.verification) {
192
+ return `## Verification Failed\n\n${result.error?.message || "Unknown error"}`;
193
+ }
194
+ const v = result.verification;
195
+ const deltaSign = v.score_delta.delta >= 0 ? "+" : "";
196
+ const lines = [
197
+ "## Verification Result",
198
+ "",
199
+ `**Issue Fixed:** ${v.issue_fixed ? "Yes" : "No"}`,
200
+ `**Score Delta:** ${boldColor(String(v.score_delta.before), scoreColor(v.score_delta.before))} -> ${boldColor(String(v.score_delta.after), scoreColor(v.score_delta.after))} (${deltaSign}${v.score_delta.delta})`,
201
+ `**Component:** ${v.component_audited}`,
202
+ `**Duration:** ${v.duration_ms}ms`,
203
+ ];
204
+ if (v.regressions.length > 0) {
205
+ lines.push("", "### Regressions");
206
+ for (const r of v.regressions) {
207
+ lines.push(`- [${r.impact.toUpperCase()}] ${r.rule_id}: ${r.description}`);
208
+ }
209
+ }
210
+ else {
211
+ lines.push("", "### Regressions", "None");
212
+ }
213
+ if (v.error) {
214
+ lines.push("", `**Warning:** ${v.error}`);
215
+ }
216
+ return lines.join("\n");
217
+ }
218
+ // Auto-fixable issue types (from lib/patch/classifier.ts)
219
+ const AUTO_FIXABLE_TYPES = new Set([
220
+ "label",
221
+ "input-missing-label",
222
+ "form-field-label",
223
+ "button-name",
224
+ "missing-button-name",
225
+ "link-name",
226
+ "html-has-lang",
227
+ "missing-lang-attribute",
228
+ "html-lang-valid",
229
+ "document-title",
230
+ "bypass",
231
+ "region",
232
+ "landmark-one-main",
233
+ "color-contrast",
234
+ "autocomplete-valid",
235
+ "aria-required-attr",
236
+ "aria-valid-attr",
237
+ "aria-valid-attr-value",
238
+ ]);
239
+ export function isAutoFixable(issueType) {
240
+ const normalized = issueType.toLowerCase().replace(/^(axe|wcag)-/, "");
241
+ return AUTO_FIXABLE_TYPES.has(normalized);
242
+ }
243
+ export function formatBatchMarkdown(results) {
244
+ const lines = [
245
+ "## Batch Patch Results",
246
+ "",
247
+ `**Total Requested:** ${results.totalRequested}`,
248
+ `**Succeeded:** ${results.successes.length}`,
249
+ `**Failed:** ${results.failures.length}`,
250
+ `**Skipped:** ${results.totalSkipped}`,
251
+ ];
252
+ if (results.successes.length > 0) {
253
+ lines.push("", "### Successful Patches");
254
+ for (const s of results.successes) {
255
+ const conf = s.patch?.confidence;
256
+ const cls = s.patch?.classification || "unknown";
257
+ const confStr = conf ? `${conf.label} (${conf.percentage}%)` : "n/a";
258
+ lines.push(`- ${s.issueId}: ${confStr} [${cls}]`);
259
+ }
260
+ }
261
+ if (results.failures.length > 0) {
262
+ lines.push("", "### Failed");
263
+ for (const f of results.failures) {
264
+ const details = f.details ? ` - ${f.details}` : "";
265
+ lines.push(`- ${f.issueId}: ${f.reason}${details}`);
266
+ }
267
+ }
268
+ return lines.join("\n");
269
+ }
270
+ export function printOutput(format, data, markdown) {
271
+ if (format === "json") {
272
+ process.stdout.write(JSON.stringify(data, null, 2) + "\n");
273
+ return;
274
+ }
275
+ // Route through writeOutput so interactive mode can buffer the output
276
+ writeOutput(markdown || "");
277
+ }
@@ -0,0 +1,12 @@
1
+ export declare function hasHelpOrVersionFlag(args: string[]): boolean;
2
+ /**
3
+ * Return the first non-option token after skipping root global options.
4
+ *
5
+ * This keeps the "launch interactive app when no command is present" behavior
6
+ * while still allowing global flags to appear before the subcommand:
7
+ *
8
+ * vertaa --machine doctor
9
+ * vertaa --base https://api.example.test audit https://example.com
10
+ */
11
+ export declare function getRootCommandToken(args: string[]): string | undefined;
12
+ //# sourceMappingURL=root-args.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"root-args.d.ts","sourceRoot":"","sources":["../../src/utils/root-args.ts"],"names":[],"mappings":"AAcA,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAE5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAyBtE"}
@@ -0,0 +1,44 @@
1
+ const ROOT_OPTIONS_WITH_VALUES = new Set([
2
+ "-b",
3
+ "--base",
4
+ "-c",
5
+ "--config",
6
+ ]);
7
+ const HELP_OR_VERSION_FLAGS = new Set([
8
+ "-h",
9
+ "--help",
10
+ "-v",
11
+ "--version",
12
+ ]);
13
+ export function hasHelpOrVersionFlag(args) {
14
+ return args.some((arg) => HELP_OR_VERSION_FLAGS.has(arg));
15
+ }
16
+ /**
17
+ * Return the first non-option token after skipping root global options.
18
+ *
19
+ * This keeps the "launch interactive app when no command is present" behavior
20
+ * while still allowing global flags to appear before the subcommand:
21
+ *
22
+ * vertaa --machine doctor
23
+ * vertaa --base https://api.example.test audit https://example.com
24
+ */
25
+ export function getRootCommandToken(args) {
26
+ for (let i = 0; i < args.length; i++) {
27
+ const arg = args[i];
28
+ if (arg === "--") {
29
+ return args[i + 1];
30
+ }
31
+ if (ROOT_OPTIONS_WITH_VALUES.has(arg)) {
32
+ i++;
33
+ continue;
34
+ }
35
+ if (arg.startsWith("--base=") || arg.startsWith("--config=")) {
36
+ continue;
37
+ }
38
+ if (arg.startsWith("-")) {
39
+ continue;
40
+ }
41
+ return arg;
42
+ }
43
+ return undefined;
44
+ }
@@ -16,6 +16,13 @@ export interface StdinResult {
16
16
  /** Whether the input was valid JSON */
17
17
  isJson: boolean;
18
18
  }
19
+ /**
20
+ * Unwrap the standard CLI JSON envelope shape ({ meta, data }).
21
+ *
22
+ * Commands that consume the output of other VertaaUX commands usually want
23
+ * the payload under `data`, not the outer provenance metadata.
24
+ */
25
+ export declare function unwrapJsonEnvelope<T = unknown>(input: unknown): T;
19
26
  /**
20
27
  * Check if stdin has piped data available.
21
28
  */
@@ -1 +1 @@
1
- {"version":3,"file":"stdin.d.ts","sourceRoot":"","sources":["../../src/utils/stdin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,0DAA0D;IAC1D,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IACrB,uCAAuC;IACvC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA2B7D;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CA+B9E;AAED;;;;GAIG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAG5D"}
1
+ {"version":3,"file":"stdin.d.ts","sourceRoot":"","sources":["../../src/utils/stdin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,0DAA0D;IAC1D,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IACrB,uCAAuC;IACvC,MAAM,EAAE,OAAO,CAAC;CACjB;AAqBD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,CAAC,CAKjE;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA2B7D;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CA+B9E;AAED;;;;GAIG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAG5D"}
@@ -5,6 +5,36 @@
5
5
  * and provides a consistent interface for all commands that accept
6
6
  * piped data (explain, triage, fix-plan, patch-review, etc.).
7
7
  */
8
+ /**
9
+ * Detect the standard CLI JSON envelope shape ({ meta, data }).
10
+ *
11
+ * Only matches when `meta` contains `command` and `version` — the fields
12
+ * that `createEnvelope()` always emits — so legitimate JSON payloads that
13
+ * happen to have a top-level `data` key are left untouched.
14
+ */
15
+ function isVertaaEnvelope(input) {
16
+ if (!input || typeof input !== "object" || !("meta" in input) || !("data" in input)) {
17
+ return false;
18
+ }
19
+ const meta = input.meta;
20
+ if (!meta || typeof meta !== "object") {
21
+ return false;
22
+ }
23
+ const { command, version } = meta;
24
+ return command !== undefined && version !== undefined;
25
+ }
26
+ /**
27
+ * Unwrap the standard CLI JSON envelope shape ({ meta, data }).
28
+ *
29
+ * Commands that consume the output of other VertaaUX commands usually want
30
+ * the payload under `data`, not the outer provenance metadata.
31
+ */
32
+ export function unwrapJsonEnvelope(input) {
33
+ if (isVertaaEnvelope(input)) {
34
+ return input.data;
35
+ }
36
+ return input;
37
+ }
8
38
  /**
9
39
  * Check if stdin has piped data available.
10
40
  */
@@ -64,7 +94,7 @@ export async function readJsonInput(filePath) {
64
94
  }
65
95
  const content = fs.readFileSync(resolved, "utf-8");
66
96
  try {
67
- return JSON.parse(content);
97
+ return unwrapJsonEnvelope(JSON.parse(content));
68
98
  }
69
99
  catch {
70
100
  throw new Error(`Invalid JSON in file: ${filePath}`);
@@ -77,7 +107,7 @@ export async function readJsonInput(filePath) {
77
107
  throw new Error("Could not parse input as JSON. If piping from vertaa, use --json flag:\n" +
78
108
  " vertaa audit https://example.com --json | vertaa explain");
79
109
  }
80
- return stdin.json;
110
+ return unwrapJsonEnvelope(stdin.json);
81
111
  }
82
112
  // No input found
83
113
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"url-classify.d.ts","sourceRoot":"","sources":["../../src/utils/url-classify.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;AAEzD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CA2BtD;AA4CD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAGrD"}
1
+ {"version":3,"file":"url-classify.d.ts","sourceRoot":"","sources":["../../src/utils/url-classify.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;AAEzD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CA8BtD;AAgED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAGrD"}
@@ -25,9 +25,12 @@ export function classifyUrl(urlString) {
25
25
  hostname.endsWith(".localhost")) {
26
26
  return "localhost";
27
27
  }
28
- // IP literal check
29
- if (net.isIP(hostname)) {
30
- if (isPrivateIp(hostname))
28
+ // IP literal check — strip brackets from IPv6 literals
29
+ const ip = hostname.startsWith("[") && hostname.endsWith("]")
30
+ ? hostname.slice(1, -1)
31
+ : hostname;
32
+ if (net.isIP(ip)) {
33
+ if (isPrivateIp(ip))
31
34
  return "private";
32
35
  return "public";
33
36
  }
@@ -40,6 +43,24 @@ function isPrivateIp(address) {
40
43
  const version = net.isIP(address);
41
44
  if (version === 6) {
42
45
  const lower = address.toLowerCase();
46
+ // IPv4-mapped IPv6 — extract and check as IPv4
47
+ // Handles both dotted form (::ffff:127.0.0.1) and hex form (::ffff:7f00:1)
48
+ if (lower.startsWith("::ffff:")) {
49
+ const mapped = lower.slice(7); // strip "::ffff:"
50
+ if (net.isIPv4(mapped)) {
51
+ return isPrivateIp(mapped);
52
+ }
53
+ // Hex form: two 16-bit groups (e.g. "7f00:1" = 127.0.0.1)
54
+ const hexParts = mapped.split(":");
55
+ if (hexParts.length === 2) {
56
+ const hi = parseInt(hexParts[0], 16);
57
+ const lo = parseInt(hexParts[1], 16);
58
+ if (!isNaN(hi) && !isNaN(lo) && hi <= 0xffff && lo <= 0xffff) {
59
+ const ipv4 = `${(hi >> 8) & 0xff}.${hi & 0xff}.${(lo >> 8) & 0xff}.${lo & 0xff}`;
60
+ return isPrivateIp(ipv4);
61
+ }
62
+ }
63
+ }
43
64
  return (lower === "::" ||
44
65
  lower === "::1" ||
45
66
  lower.startsWith("fc") ||