@vertaaux/cli 0.3.3 → 0.5.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 (227) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/MIGRATION.md +239 -0
  3. package/README.md +34 -16
  4. package/dist/app/interactive-app.d.ts +101 -0
  5. package/dist/app/interactive-app.d.ts.map +1 -0
  6. package/dist/app/interactive-app.js +309 -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 +181 -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 +372 -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 +45 -0
  37. package/dist/auth/ci-token.d.ts +14 -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 +9 -0
  49. package/dist/commands/a11y.d.ts.map +1 -0
  50. package/dist/commands/a11y.js +76 -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 +564 -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 +130 -0
  69. package/dist/commands/audit/policy.d.ts +19 -0
  70. package/dist/commands/audit/policy.d.ts.map +1 -0
  71. package/dist/commands/audit/policy.js +102 -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 +88 -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 -1038
  81. package/dist/commands/baseline.d.ts +1 -0
  82. package/dist/commands/baseline.d.ts.map +1 -1
  83. package/dist/commands/baseline.js +205 -121
  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 +122 -58
  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 +287 -180
  90. package/dist/commands/diff.d.ts +5 -0
  91. package/dist/commands/diff.d.ts.map +1 -1
  92. package/dist/commands/diff.js +168 -141
  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 +134 -76
  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 +164 -17
  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 +241 -155
  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 +152 -89
  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 +268 -95
  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 +159 -97
  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 +269 -124
  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 +127 -73
  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 +153 -82
  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 +206 -81
  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/index.d.ts +3 -2
  148. package/dist/index.d.ts.map +1 -1
  149. package/dist/index.js +125 -990
  150. package/dist/interactive/fix-wizard.d.ts +3 -0
  151. package/dist/interactive/fix-wizard.d.ts.map +1 -1
  152. package/dist/interactive/fix-wizard.js +130 -112
  153. package/dist/interactive/init-wizard.d.ts +3 -1
  154. package/dist/interactive/init-wizard.d.ts.map +1 -1
  155. package/dist/interactive/init-wizard.js +207 -138
  156. package/dist/interactive/prompts.d.ts +7 -3
  157. package/dist/interactive/prompts.d.ts.map +1 -1
  158. package/dist/interactive/prompts.js +44 -23
  159. package/dist/output/envelope.d.ts +2 -0
  160. package/dist/output/envelope.d.ts.map +1 -1
  161. package/dist/output/envelope.js +18 -2
  162. package/dist/output/factory.d.ts +9 -1
  163. package/dist/output/factory.d.ts.map +1 -1
  164. package/dist/output/html.d.ts +2 -1
  165. package/dist/output/html.d.ts.map +1 -1
  166. package/dist/output/html.js +3 -2
  167. package/dist/output/human.d.ts +9 -1
  168. package/dist/output/human.d.ts.map +1 -1
  169. package/dist/output/human.js +17 -2
  170. package/dist/output/json.d.ts +2 -1
  171. package/dist/output/json.d.ts.map +1 -1
  172. package/dist/output/junit.d.ts +2 -1
  173. package/dist/output/junit.d.ts.map +1 -1
  174. package/dist/output/sarif.d.ts +2 -1
  175. package/dist/output/sarif.d.ts.map +1 -1
  176. package/dist/types.d.ts +74 -0
  177. package/dist/types.d.ts.map +1 -0
  178. package/dist/types.js +5 -0
  179. package/dist/ui/banner.d.ts +34 -0
  180. package/dist/ui/banner.d.ts.map +1 -1
  181. package/dist/ui/banner.js +97 -5
  182. package/dist/ui/diagnostics.d.ts +9 -4
  183. package/dist/ui/diagnostics.d.ts.map +1 -1
  184. package/dist/ui/diagnostics.js +32 -82
  185. package/dist/ui/strings.d.ts +373 -0
  186. package/dist/ui/strings.d.ts.map +1 -0
  187. package/dist/ui/strings.js +499 -0
  188. package/dist/ui/table.d.ts +0 -2
  189. package/dist/ui/table.d.ts.map +1 -1
  190. package/dist/ui/table.js +3 -4
  191. package/dist/utils/api-client.d.ts +46 -0
  192. package/dist/utils/api-client.d.ts.map +1 -0
  193. package/dist/utils/api-client.js +170 -0
  194. package/dist/utils/client.d.ts +29 -18
  195. package/dist/utils/client.d.ts.map +1 -1
  196. package/dist/utils/client.js +102 -12
  197. package/dist/utils/formatters.d.ts +38 -0
  198. package/dist/utils/formatters.d.ts.map +1 -0
  199. package/dist/utils/formatters.js +277 -0
  200. package/dist/utils/local-capture.d.ts +25 -0
  201. package/dist/utils/local-capture.d.ts.map +1 -0
  202. package/dist/utils/local-capture.js +57 -0
  203. package/dist/utils/url-classify.d.ts +18 -0
  204. package/dist/utils/url-classify.d.ts.map +1 -0
  205. package/dist/utils/url-classify.js +106 -0
  206. package/node_modules/@vertaaux/tui/dist/index.cjs +713 -20
  207. package/node_modules/@vertaaux/tui/dist/index.cjs.map +1 -1
  208. package/node_modules/@vertaaux/tui/dist/index.d.cts +361 -4
  209. package/node_modules/@vertaaux/tui/dist/index.d.ts +361 -4
  210. package/node_modules/@vertaaux/tui/dist/index.js +689 -21
  211. package/node_modules/@vertaaux/tui/dist/index.js.map +1 -1
  212. package/package.json +13 -5
  213. package/dist/commands/client.d.ts +0 -14
  214. package/dist/commands/client.d.ts.map +0 -1
  215. package/dist/commands/client.js +0 -362
  216. package/dist/commands/drift.d.ts +0 -15
  217. package/dist/commands/drift.d.ts.map +0 -1
  218. package/dist/commands/drift.js +0 -309
  219. package/dist/commands/protect.d.ts +0 -16
  220. package/dist/commands/protect.d.ts.map +0 -1
  221. package/dist/commands/protect.js +0 -323
  222. package/dist/commands/report.d.ts +0 -15
  223. package/dist/commands/report.d.ts.map +0 -1
  224. package/dist/commands/report.js +0 -214
  225. package/dist/policy/sync.d.ts +0 -67
  226. package/dist/policy/sync.d.ts.map +0 -1
  227. package/dist/policy/sync.js +0 -147
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Command category definitions for the interactive menu.
3
+ *
4
+ * 6 groups of 24 commands matching Commander.js registrations in index.ts.
5
+ * Each MenuItem.value must exactly match the Commander command name.
6
+ */
7
+ /**
8
+ * All 24 commands organized into 6 semantic groups.
9
+ *
10
+ * Groups follow a natural user workflow:
11
+ * Audit → Results → Fixes → Reports → Project → Account
12
+ */
13
+ export const COMMAND_CATEGORIES = [
14
+ {
15
+ label: "Audit",
16
+ items: [
17
+ {
18
+ name: "Run Audit",
19
+ value: "audit",
20
+ description: "Audit a URL for UX and accessibility issues",
21
+ },
22
+ {
23
+ name: "Quick Scan",
24
+ value: "scan",
25
+ description: "Fast page scan without full audit pipeline",
26
+ },
27
+ {
28
+ name: "Accessibility Check",
29
+ value: "a11y",
30
+ description: "Run WCAG accessibility checks on a URL",
31
+ },
32
+ ],
33
+ },
34
+ {
35
+ label: "Results",
36
+ items: [
37
+ {
38
+ name: "Check Status",
39
+ value: "status",
40
+ description: "Check status of a running or completed audit job",
41
+ },
42
+ {
43
+ name: "Show Diff",
44
+ value: "diff",
45
+ description: "Compare audit results between two runs",
46
+ },
47
+ {
48
+ name: "Compare Pages",
49
+ value: "compare",
50
+ description: "Compare UX scores across multiple pages",
51
+ },
52
+ {
53
+ name: "Triage Issues",
54
+ value: "triage",
55
+ description: "Interactive triage of audit findings",
56
+ },
57
+ {
58
+ name: "Explain Issue",
59
+ value: "explain",
60
+ description: "Get plain-language explanation of an audit finding",
61
+ },
62
+ ],
63
+ },
64
+ {
65
+ label: "Fixes",
66
+ items: [
67
+ {
68
+ name: "Suggest Fix",
69
+ value: "suggest",
70
+ description: "Get AI-suggested fix for a specific issue",
71
+ },
72
+ {
73
+ name: "Apply Fix",
74
+ value: "fix",
75
+ description: "Apply a suggested fix to your codebase",
76
+ },
77
+ {
78
+ name: "Fix All",
79
+ value: "fix-all",
80
+ description: "Apply all suggested fixes in one pass",
81
+ },
82
+ {
83
+ name: "Fix Plan",
84
+ value: "fix-plan",
85
+ description: "Generate a structured remediation plan",
86
+ },
87
+ {
88
+ name: "Review Patch",
89
+ value: "patch-review",
90
+ description: "Review a generated patch before applying",
91
+ },
92
+ ],
93
+ },
94
+ {
95
+ label: "Reports",
96
+ items: [
97
+ {
98
+ name: "Generate Doc",
99
+ value: "doc",
100
+ description: "Generate accessibility documentation for a component",
101
+ },
102
+ {
103
+ name: "Add Comment",
104
+ value: "comment",
105
+ description: "Add audit annotations to source code",
106
+ },
107
+ {
108
+ name: "Release Notes",
109
+ value: "release-notes",
110
+ description: "Generate release notes from audit improvements",
111
+ },
112
+ ],
113
+ },
114
+ {
115
+ label: "Project",
116
+ items: [
117
+ {
118
+ name: "Initialize",
119
+ value: "init",
120
+ description: "Create .vertaaux.yml configuration in current project",
121
+ },
122
+ {
123
+ name: "Set Baseline",
124
+ value: "baseline",
125
+ description: "Set current audit results as the project baseline",
126
+ },
127
+ {
128
+ name: "Upload Results",
129
+ value: "upload",
130
+ description: "Upload local audit results to VertaaUX cloud",
131
+ },
132
+ {
133
+ name: "Download Results",
134
+ value: "download",
135
+ description: "Download audit results from VertaaUX cloud",
136
+ },
137
+ {
138
+ name: "Verify Quality Gate",
139
+ value: "verify",
140
+ description: "Check if results meet quality gate thresholds",
141
+ },
142
+ ],
143
+ },
144
+ {
145
+ label: "Account",
146
+ items: [
147
+ {
148
+ name: "Login",
149
+ value: "login",
150
+ description: "Authenticate with your VertaaUX account",
151
+ },
152
+ {
153
+ name: "Logout",
154
+ value: "logout",
155
+ description: "Sign out and remove stored credentials",
156
+ },
157
+ {
158
+ name: "Who Am I",
159
+ value: "whoami",
160
+ description: "Show currently authenticated account",
161
+ },
162
+ {
163
+ name: "Health Check",
164
+ value: "doctor",
165
+ description: "Run diagnostics on CLI configuration and connectivity",
166
+ },
167
+ {
168
+ name: "Policy",
169
+ value: "policy",
170
+ description: "Manage project quality gate policies",
171
+ },
172
+ ],
173
+ },
174
+ ];
175
+ /**
176
+ * Returns a flat list of all MenuItem entries across all categories.
177
+ * Useful for quick lookups by command value.
178
+ */
179
+ export function allMenuItems() {
180
+ return COMMAND_CATEGORIES.flatMap((cat) => cat.items);
181
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Type-to-filter search logic for the interactive menu.
3
+ *
4
+ * Filters command categories by a case-insensitive substring query.
5
+ * Matches against item name, value, and description.
6
+ * Returns only categories with at least one matching item, preserving order.
7
+ */
8
+ import type { CommandCategory } from "../types.js";
9
+ /**
10
+ * Filter categories by a search query.
11
+ *
12
+ * @param query - The search string (case-insensitive substring match)
13
+ * @param categories - Source categories to filter
14
+ * @returns Categories (and filtered items) matching the query; empty query returns all unchanged
15
+ */
16
+ export declare function filterCategories(query: string, categories: CommandCategory[]): CommandCategory[];
17
+ //# sourceMappingURL=filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../../src/app/menu/filter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,eAAe,EAAE,GAC5B,eAAe,EAAE,CAyBnB"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Type-to-filter search logic for the interactive menu.
3
+ *
4
+ * Filters command categories by a case-insensitive substring query.
5
+ * Matches against item name, value, and description.
6
+ * Returns only categories with at least one matching item, preserving order.
7
+ */
8
+ /**
9
+ * Filter categories by a search query.
10
+ *
11
+ * @param query - The search string (case-insensitive substring match)
12
+ * @param categories - Source categories to filter
13
+ * @returns Categories (and filtered items) matching the query; empty query returns all unchanged
14
+ */
15
+ export function filterCategories(query, categories) {
16
+ // Empty query — return all categories unchanged
17
+ if (query.trim() === "") {
18
+ return categories;
19
+ }
20
+ const lowerQuery = query.toLowerCase();
21
+ const result = [];
22
+ for (const category of categories) {
23
+ const matchingItems = category.items.filter((item) => {
24
+ return (item.name.toLowerCase().includes(lowerQuery) ||
25
+ item.value.toLowerCase().includes(lowerQuery) ||
26
+ (item.description?.toLowerCase().includes(lowerQuery) ?? false));
27
+ });
28
+ if (matchingItems.length > 0) {
29
+ result.push({ label: category.label, items: matchingItems });
30
+ }
31
+ }
32
+ return result;
33
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * MenuView — Two-level drilldown command menu.
3
+ *
4
+ * Level 1: 6 category groups (Audit, Results, Fixes, Reports, Project, Account)
5
+ * Level 2: Commands within the selected category
6
+ *
7
+ * Navigation:
8
+ * ↑↓ — move selection
9
+ * Enter — drill into category / run command
10
+ * Escape — back to categories (or clear search)
11
+ * Type — search across all commands (flat filtered list)
12
+ */
13
+ import type { CommandView } from "../types.js";
14
+ export declare class MenuView implements CommandView {
15
+ private searchBuffer;
16
+ private selectedIndex;
17
+ private level;
18
+ private activeCategory;
19
+ private readonly onSelect;
20
+ private cachedSearchQuery;
21
+ private cachedSearchItems;
22
+ constructor(onSelect: (command: string) => void);
23
+ render(): string;
24
+ handleKey(key: string, ctrl: boolean, _meta: boolean): boolean;
25
+ private renderCategories;
26
+ private renderItems;
27
+ private renderSearch;
28
+ private renderMenuItem;
29
+ private getSearchItems;
30
+ private moveCursor;
31
+ private getItemCount;
32
+ private confirmSelection;
33
+ private goBack;
34
+ }
35
+ //# sourceMappingURL=menu-view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menu-view.d.ts","sourceRoot":"","sources":["../../../src/app/menu/menu-view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,WAAW,EAA6B,MAAM,aAAa,CAAC;AAa1E,qBAAa,QAAS,YAAW,WAAW;IAC1C,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,cAAc,CAAgC;IACtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IAGrD,OAAO,CAAC,iBAAiB,CAAM;IAC/B,OAAO,CAAC,iBAAiB,CAAkB;gBAE/B,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI;IAK/C,MAAM,IAAI,MAAM;IAUhB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO;IAiD9D,OAAO,CAAC,gBAAgB;IA0BxB,OAAO,CAAC,WAAW;IA4BnB,OAAO,CAAC,YAAY;IA8BpB,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,gBAAgB;IA8BxB,OAAO,CAAC,MAAM;CAmBf"}
@@ -0,0 +1,230 @@
1
+ /**
2
+ * MenuView — Two-level drilldown command menu.
3
+ *
4
+ * Level 1: 6 category groups (Audit, Results, Fixes, Reports, Project, Account)
5
+ * Level 2: Commands within the selected category
6
+ *
7
+ * Navigation:
8
+ * ↑↓ — move selection
9
+ * Enter — drill into category / run command
10
+ * Escape — back to categories (or clear search)
11
+ * Type — search across all commands (flat filtered list)
12
+ */
13
+ import { bold, colorize, dim, brand } from "@vertaaux/tui";
14
+ import { COMMAND_CATEGORIES } from "./categories.js";
15
+ import { filterCategories } from "./filter.js";
16
+ const UP_ARROW = "\x1b[A";
17
+ const DOWN_ARROW = "\x1b[B";
18
+ // Pre-computed: category label column width (static, never changes)
19
+ const CATEGORY_COL_WIDTH = Math.max(...COMMAND_CATEGORIES.map(c => c.label.length)) + 4;
20
+ export class MenuView {
21
+ searchBuffer = "";
22
+ selectedIndex = 0;
23
+ level = "categories";
24
+ activeCategory = null;
25
+ onSelect;
26
+ // Cached search results — invalidated when searchBuffer changes
27
+ cachedSearchQuery = "";
28
+ cachedSearchItems = [];
29
+ constructor(onSelect) {
30
+ this.onSelect = onSelect;
31
+ }
32
+ render() {
33
+ if (this.searchBuffer) {
34
+ return this.renderSearch();
35
+ }
36
+ if (this.level === "items" && this.activeCategory) {
37
+ return this.renderItems();
38
+ }
39
+ return this.renderCategories();
40
+ }
41
+ handleKey(key, ctrl, _meta) {
42
+ if (ctrl && key === "\x03")
43
+ return false;
44
+ if (key === UP_ARROW) {
45
+ this.moveCursor(-1);
46
+ return true;
47
+ }
48
+ if (key === DOWN_ARROW) {
49
+ this.moveCursor(1);
50
+ return true;
51
+ }
52
+ if (key === "\r" || key === "\n") {
53
+ this.confirmSelection();
54
+ return true;
55
+ }
56
+ if (key === "\x1b") {
57
+ return this.goBack();
58
+ }
59
+ if (key === "\x7f" || key === "\b") {
60
+ if (this.searchBuffer.length > 0) {
61
+ this.searchBuffer = this.searchBuffer.slice(0, -1);
62
+ this.selectedIndex = 0;
63
+ if (this.searchBuffer === "") {
64
+ this.level = "categories";
65
+ }
66
+ }
67
+ else if (this.level === "items") {
68
+ this.level = "categories";
69
+ this.activeCategory = null;
70
+ this.selectedIndex = 0;
71
+ }
72
+ return true;
73
+ }
74
+ // Printable character — enter search mode
75
+ if (key.length === 1 && key >= " ") {
76
+ this.searchBuffer += key;
77
+ this.level = "search";
78
+ this.selectedIndex = 0;
79
+ return true;
80
+ }
81
+ return false;
82
+ }
83
+ // ── Render methods ────────────────────────────────────────────
84
+ renderCategories() {
85
+ const lines = [
86
+ dim("Type to search commands..."),
87
+ "",
88
+ ];
89
+ const count = COMMAND_CATEGORIES.length;
90
+ if (this.selectedIndex >= count)
91
+ this.selectedIndex = count - 1;
92
+ for (let i = 0; i < count; i++) {
93
+ const cat = COMMAND_CATEGORIES[i];
94
+ const isSelected = i === this.selectedIndex;
95
+ const padding = " ".repeat(CATEGORY_COL_WIDTH - cat.label.length);
96
+ const label = isSelected
97
+ ? bold(colorize(` ${cat.label}`, brand.lime))
98
+ : ` ${cat.label}`;
99
+ const itemCount = dim(`${cat.items.length} commands`);
100
+ lines.push(label + padding + itemCount);
101
+ }
102
+ lines.push("");
103
+ lines.push(dim("↑↓ navigate ↵ open type to search"));
104
+ return lines.join("\n");
105
+ }
106
+ renderItems() {
107
+ const cat = this.activeCategory;
108
+ if (!cat)
109
+ return "";
110
+ const lines = [
111
+ bold(cat.label),
112
+ "",
113
+ ];
114
+ const nameColWidth = Math.max(...cat.items.map(i => i.name.length), 10) + 4;
115
+ if (this.selectedIndex >= cat.items.length) {
116
+ this.selectedIndex = cat.items.length - 1;
117
+ }
118
+ for (let i = 0; i < cat.items.length; i++) {
119
+ const item = cat.items[i];
120
+ const isSelected = i === this.selectedIndex;
121
+ lines.push(this.renderMenuItem(item, isSelected, nameColWidth));
122
+ }
123
+ lines.push("");
124
+ lines.push(dim("↑↓ navigate ↵ run Esc back"));
125
+ return lines.join("\n");
126
+ }
127
+ renderSearch() {
128
+ const lines = [
129
+ `Search: ${this.searchBuffer}_`,
130
+ "",
131
+ ];
132
+ const flatItems = this.getSearchItems();
133
+ if (this.selectedIndex >= flatItems.length) {
134
+ this.selectedIndex = Math.max(0, flatItems.length - 1);
135
+ }
136
+ if (flatItems.length === 0) {
137
+ lines.push(dim(" No commands match your search."));
138
+ }
139
+ else {
140
+ const nameColWidth = Math.max(...flatItems.map(i => i.name.length), 10) + 4;
141
+ for (let i = 0; i < flatItems.length; i++) {
142
+ lines.push(this.renderMenuItem(flatItems[i], i === this.selectedIndex, nameColWidth));
143
+ }
144
+ }
145
+ lines.push("");
146
+ lines.push(dim("↑↓ navigate ↵ run Esc clear"));
147
+ return lines.join("\n");
148
+ }
149
+ renderMenuItem(item, selected, nameColWidth) {
150
+ const indent = " ";
151
+ const nameText = item.name;
152
+ const padding = " ".repeat(Math.max(2, nameColWidth - indent.length - nameText.length));
153
+ const name = selected
154
+ ? bold(colorize(`${indent}${nameText}`, brand.lime))
155
+ : `${indent}${nameText}`;
156
+ const desc = item.description ? dim(item.description) : "";
157
+ return name + padding + desc;
158
+ }
159
+ // ── Search cache ────────────────────────────────────────────
160
+ getSearchItems() {
161
+ if (this.cachedSearchQuery !== this.searchBuffer) {
162
+ this.cachedSearchQuery = this.searchBuffer;
163
+ this.cachedSearchItems = filterCategories(this.searchBuffer, COMMAND_CATEGORIES)
164
+ .flatMap(c => c.items);
165
+ }
166
+ return this.cachedSearchItems;
167
+ }
168
+ // ── Navigation helpers ────────────────────────────────────────
169
+ moveCursor(delta) {
170
+ const count = this.getItemCount();
171
+ if (count === 0)
172
+ return;
173
+ this.selectedIndex = (this.selectedIndex + delta + count) % count;
174
+ }
175
+ getItemCount() {
176
+ if (this.searchBuffer) {
177
+ return this.getSearchItems().length;
178
+ }
179
+ if (this.level === "items" && this.activeCategory) {
180
+ return this.activeCategory.items.length;
181
+ }
182
+ return COMMAND_CATEGORIES.length;
183
+ }
184
+ confirmSelection() {
185
+ if (this.searchBuffer) {
186
+ // Search mode — select a command directly
187
+ const flatItems = this.getSearchItems();
188
+ if (flatItems[this.selectedIndex]) {
189
+ this.onSelect(flatItems[this.selectedIndex].value);
190
+ }
191
+ return;
192
+ }
193
+ if (this.level === "categories") {
194
+ // Drill into category
195
+ const cat = COMMAND_CATEGORIES[this.selectedIndex];
196
+ if (cat) {
197
+ this.activeCategory = cat;
198
+ this.level = "items";
199
+ this.selectedIndex = 0;
200
+ }
201
+ return;
202
+ }
203
+ if (this.level === "items" && this.activeCategory) {
204
+ // Select a command
205
+ const item = this.activeCategory.items[this.selectedIndex];
206
+ if (item) {
207
+ this.onSelect(item.value);
208
+ }
209
+ }
210
+ }
211
+ goBack() {
212
+ if (this.searchBuffer) {
213
+ this.searchBuffer = "";
214
+ this.selectedIndex = 0;
215
+ this.level = "categories";
216
+ return true;
217
+ }
218
+ if (this.level === "items") {
219
+ // Find the index of the active category to restore position
220
+ const catIndex = this.activeCategory
221
+ ? COMMAND_CATEGORIES.indexOf(this.activeCategory)
222
+ : -1;
223
+ this.level = "categories";
224
+ this.activeCategory = null;
225
+ this.selectedIndex = catIndex >= 0 ? catIndex : 0;
226
+ return true;
227
+ }
228
+ return false;
229
+ }
230
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Recent commands persistence for the interactive menu.
3
+ *
4
+ * Persists the last 5 commands to ~/.vertaaux/recent.json.
5
+ * Deduplicates and caps at 5 entries.
6
+ */
7
+ /** Path to the recent commands JSON file */
8
+ export declare const RECENT_PATH: string;
9
+ /**
10
+ * Load the recent commands list from disk.
11
+ *
12
+ * Returns an empty array if the file does not exist or contains invalid JSON.
13
+ */
14
+ export declare function loadRecent(): Promise<string[]>;
15
+ /**
16
+ * Record a command as recently used.
17
+ *
18
+ * Prepends the command to the list, deduplicates (case-sensitive),
19
+ * caps at RECENT_MAX, and writes to disk. Creates the directory if needed.
20
+ *
21
+ * @param command - The command value (e.g., "audit", "doctor")
22
+ */
23
+ export declare function recordRecent(command: string): Promise<void>;
24
+ //# sourceMappingURL=recent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recent.d.ts","sourceRoot":"","sources":["../../../src/app/menu/recent.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,4CAA4C;AAC5C,eAAO,MAAM,WAAW,QAA8C,CAAC;AAEvE;;;;GAIG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAWpD;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAajE"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Recent commands persistence for the interactive menu.
3
+ *
4
+ * Persists the last 5 commands to ~/.vertaaux/recent.json.
5
+ * Deduplicates and caps at 5 entries.
6
+ */
7
+ import { join } from "path";
8
+ import { homedir } from "os";
9
+ import * as fsp from "fs/promises";
10
+ /** Maximum number of recent commands to retain */
11
+ const RECENT_MAX = 5;
12
+ /** Path to the recent commands JSON file */
13
+ export const RECENT_PATH = join(homedir(), ".vertaaux", "recent.json");
14
+ /**
15
+ * Load the recent commands list from disk.
16
+ *
17
+ * Returns an empty array if the file does not exist or contains invalid JSON.
18
+ */
19
+ export async function loadRecent() {
20
+ try {
21
+ const raw = await fsp.readFile(RECENT_PATH, "utf-8");
22
+ const parsed = JSON.parse(raw);
23
+ if (Array.isArray(parsed)) {
24
+ return parsed.filter((x) => typeof x === "string");
25
+ }
26
+ return [];
27
+ }
28
+ catch {
29
+ return [];
30
+ }
31
+ }
32
+ /**
33
+ * Record a command as recently used.
34
+ *
35
+ * Prepends the command to the list, deduplicates (case-sensitive),
36
+ * caps at RECENT_MAX, and writes to disk. Creates the directory if needed.
37
+ *
38
+ * @param command - The command value (e.g., "audit", "doctor")
39
+ */
40
+ export async function recordRecent(command) {
41
+ const existing = await loadRecent();
42
+ // Deduplicate: remove any existing occurrence of this command
43
+ const deduped = existing.filter((c) => c !== command);
44
+ // Prepend to front, cap at max
45
+ const updated = [command, ...deduped].slice(0, RECENT_MAX);
46
+ // Ensure directory exists
47
+ await fsp.mkdir(join(homedir(), ".vertaaux"), { recursive: true });
48
+ await fsp.writeFile(RECENT_PATH, JSON.stringify(updated), "utf-8");
49
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Core type contracts for the InteractiveApp shell.
3
+ *
4
+ * CommandView is the interface all interactive command views must implement.
5
+ * AppState tracks the application's current screen and active view.
6
+ */
7
+ /**
8
+ * Interface for pluggable views that can be mounted in the InteractiveApp canvas.
9
+ *
10
+ * Each view owns its rendering and keyboard handling; the app shell
11
+ * calls render() each tick and routes keyboard events to handleKey().
12
+ */
13
+ export interface CommandView {
14
+ /** Render current content as string — canvas calls this each frame */
15
+ render(): string;
16
+ /** Handle keyboard event — return true if consumed */
17
+ handleKey?(key: string, ctrl: boolean, meta: boolean): boolean;
18
+ /** Called once when view is mounted in the canvas */
19
+ onMount?(): Promise<void>;
20
+ /** Called once when view is unmounted from the canvas */
21
+ onUnmount?(): Promise<void>;
22
+ }
23
+ /** A single menu item in the interactive command menu */
24
+ export interface MenuItem {
25
+ name: string;
26
+ value: string;
27
+ description?: string;
28
+ shortcut?: string;
29
+ }
30
+ /** A category grouping for the root menu */
31
+ export interface CommandCategory {
32
+ label: string;
33
+ items: MenuItem[];
34
+ }
35
+ /** Which top-level screen the app is currently showing */
36
+ export type AppScreen = "menu" | "command" | "help";
37
+ /** Full application state passed to layout renderers */
38
+ export interface AppState {
39
+ screen: AppScreen;
40
+ statusText: string;
41
+ activeView: CommandView | null;
42
+ }
43
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/app/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,sEAAsE;IACtE,MAAM,IAAI,MAAM,CAAC;IACjB,sDAAsD;IACtD,SAAS,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IAC/D,qDAAqD;IACrD,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,yDAAyD;IACzD,SAAS,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B;AAED,yDAAyD;AACzD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED,0DAA0D;AAC1D,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpD,wDAAwD;AACxD,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,SAAS,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,WAAW,GAAG,IAAI,CAAC;CAChC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Core type contracts for the InteractiveApp shell.
3
+ *
4
+ * CommandView is the interface all interactive command views must implement.
5
+ * AppState tracks the application's current screen and active view.
6
+ */
7
+ export {};
@@ -0,0 +1,36 @@
1
+ /**
2
+ * CommandRunnerView — Executes a CLI command within the InteractiveApp canvas.
3
+ *
4
+ * Lifecycle:
5
+ * 1. "collecting" — prompts for required args ON the alt screen using raw-mode
6
+ * keyboard input (same system as MenuView). No stdin mode transitions.
7
+ * 2. "running" — command runs INSIDE the app layout. A renderer override
8
+ * captures step states so this view can render them in the canvas.
9
+ * Header and footer stay visible throughout.
10
+ * 3. "done"/"error" — shows result summary in canvas, M returns to menu.
11
+ *
12
+ * Each command's handler is called directly (no program.parse()).
13
+ */
14
+ import type { CommandView } from "../types.js";
15
+ import type { InteractiveApp } from "../interactive-app.js";
16
+ export declare class CommandRunnerView implements CommandView {
17
+ private status;
18
+ private statusText;
19
+ private commandValue;
20
+ private app;
21
+ private onReturn;
22
+ private argDefs;
23
+ private collectedArgs;
24
+ private currentArgIndex;
25
+ private inputBuffer;
26
+ private resolveArgCollection;
27
+ private canvasRenderer;
28
+ private outputBuffer;
29
+ private scrollOffset;
30
+ constructor(commandValue: string, app: InteractiveApp, onReturn: () => void);
31
+ render(): string;
32
+ handleKey(key: string, ctrl: boolean, _meta: boolean): boolean;
33
+ onMount(): Promise<void>;
34
+ private executeCommand;
35
+ }
36
+ //# sourceMappingURL=command-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-runner.d.ts","sourceRoot":"","sources":["../../../src/app/views/command-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAWH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAwF5D,qBAAa,iBAAkB,YAAW,WAAW;IACnD,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,UAAU,CAAM;IACxB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAa;IAG7B,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,WAAW,CAAM;IAGzB,OAAO,CAAC,oBAAoB,CAA6B;IAGzD,OAAO,CAAC,cAAc,CAAwB;IAG9C,OAAO,CAAC,YAAY,CAAgB;IAGpC,OAAO,CAAC,YAAY,CAAK;gBAGvB,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,cAAc,EACnB,QAAQ,EAAE,MAAM,IAAI;IAStB,MAAM,IAAI,MAAM;IA0EhB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO;IAsFxD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YA+BhB,cAAc;CA0F7B"}