@vertaaux/cli 0.2.2 → 0.3.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 (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -2
  3. package/dist/auth/device-flow.d.ts.map +1 -1
  4. package/dist/auth/device-flow.js +46 -14
  5. package/dist/commands/audit.d.ts +2 -0
  6. package/dist/commands/audit.d.ts.map +1 -1
  7. package/dist/commands/audit.js +167 -8
  8. package/dist/commands/client.d.ts +14 -0
  9. package/dist/commands/client.d.ts.map +1 -0
  10. package/dist/commands/client.js +362 -0
  11. package/dist/commands/compare.d.ts +20 -0
  12. package/dist/commands/compare.d.ts.map +1 -0
  13. package/dist/commands/compare.js +335 -0
  14. package/dist/commands/doc.d.ts +18 -0
  15. package/dist/commands/doc.d.ts.map +1 -0
  16. package/dist/commands/doc.js +161 -0
  17. package/dist/commands/download.d.ts.map +1 -1
  18. package/dist/commands/download.js +9 -8
  19. package/dist/commands/drift.d.ts +15 -0
  20. package/dist/commands/drift.d.ts.map +1 -0
  21. package/dist/commands/drift.js +309 -0
  22. package/dist/commands/explain.d.ts +14 -33
  23. package/dist/commands/explain.d.ts.map +1 -1
  24. package/dist/commands/explain.js +277 -179
  25. package/dist/commands/fix-plan.d.ts +15 -0
  26. package/dist/commands/fix-plan.d.ts.map +1 -0
  27. package/dist/commands/fix-plan.js +182 -0
  28. package/dist/commands/patch-review.d.ts +14 -0
  29. package/dist/commands/patch-review.d.ts.map +1 -0
  30. package/dist/commands/patch-review.js +200 -0
  31. package/dist/commands/protect.d.ts +16 -0
  32. package/dist/commands/protect.d.ts.map +1 -0
  33. package/dist/commands/protect.js +323 -0
  34. package/dist/commands/release-notes.d.ts +17 -0
  35. package/dist/commands/release-notes.d.ts.map +1 -0
  36. package/dist/commands/release-notes.js +145 -0
  37. package/dist/commands/report.d.ts +15 -0
  38. package/dist/commands/report.d.ts.map +1 -0
  39. package/dist/commands/report.js +214 -0
  40. package/dist/commands/suggest.d.ts +18 -0
  41. package/dist/commands/suggest.d.ts.map +1 -0
  42. package/dist/commands/suggest.js +152 -0
  43. package/dist/commands/triage.d.ts +17 -0
  44. package/dist/commands/triage.d.ts.map +1 -0
  45. package/dist/commands/triage.js +205 -0
  46. package/dist/commands/upload.d.ts.map +1 -1
  47. package/dist/commands/upload.js +8 -7
  48. package/dist/index.js +62 -25
  49. package/dist/output/formats.d.ts.map +1 -1
  50. package/dist/output/formats.js +18 -2
  51. package/dist/output/human.d.ts +1 -10
  52. package/dist/output/human.d.ts.map +1 -1
  53. package/dist/output/human.js +26 -98
  54. package/dist/policy/sync.d.ts +67 -0
  55. package/dist/policy/sync.d.ts.map +1 -0
  56. package/dist/policy/sync.js +147 -0
  57. package/dist/prompts/command-catalog.d.ts +46 -0
  58. package/dist/prompts/command-catalog.d.ts.map +1 -0
  59. package/dist/prompts/command-catalog.js +187 -0
  60. package/dist/ui/spinner.d.ts +10 -35
  61. package/dist/ui/spinner.d.ts.map +1 -1
  62. package/dist/ui/spinner.js +11 -58
  63. package/dist/ui/table.d.ts +1 -18
  64. package/dist/ui/table.d.ts.map +1 -1
  65. package/dist/ui/table.js +56 -163
  66. package/dist/utils/ai-error.d.ts +48 -0
  67. package/dist/utils/ai-error.d.ts.map +1 -0
  68. package/dist/utils/ai-error.js +190 -0
  69. package/dist/utils/detect-env.d.ts +6 -8
  70. package/dist/utils/detect-env.d.ts.map +1 -1
  71. package/dist/utils/detect-env.js +6 -25
  72. package/dist/utils/stdin.d.ts +50 -0
  73. package/dist/utils/stdin.d.ts.map +1 -0
  74. package/dist/utils/stdin.js +93 -0
  75. package/package.json +11 -7
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Policy push/pull sync module for VertaaUX CLI.
3
+ *
4
+ * Provides bidirectional sync between local policy files and the server API.
5
+ * Uses the established CLI API patterns (resolveApiBase, getApiKey, apiRequest).
6
+ *
7
+ * Implements POL-10: Policy push/pull sync.
8
+ */
9
+ import { resolveApiBase, getApiKey, apiRequest } from "../utils/client.js";
10
+ /**
11
+ * Build sync config from CLI config and environment.
12
+ * Uses the established CLI pattern: resolveApiBase + getApiKey.
13
+ */
14
+ export function buildSyncConfig(cliConfig) {
15
+ return {
16
+ apiBase: resolveApiBase(undefined, undefined),
17
+ apiKey: getApiKey(cliConfig?.apiKey),
18
+ };
19
+ }
20
+ /**
21
+ * Push a local policy file to the server.
22
+ *
23
+ * If a policy with the given name already exists, updates it (with optional
24
+ * optimistic locking via expectedVersion). Otherwise creates a new policy.
25
+ *
26
+ * @param policy - The policy content to push
27
+ * @param config - API connection config
28
+ * @param options - Push options (name, description, force, etc.)
29
+ * @returns Push result with success status, policy ID, and version
30
+ */
31
+ export async function pushPolicy(policy, config, options) {
32
+ try {
33
+ // First, try to find existing policy by name
34
+ const listData = await apiRequest(config.apiBase, "/policies", { method: "GET" }, config.apiKey);
35
+ const existing = listData.policies?.find((p) => p.name === options.name);
36
+ if (existing) {
37
+ // Update existing policy
38
+ const body = {
39
+ content: policy,
40
+ changeMessage: options.changeMessage || "Pushed from CLI",
41
+ };
42
+ if (options.expectedVersion && !options.force) {
43
+ body.expectedVersion = options.expectedVersion;
44
+ }
45
+ try {
46
+ const updated = await apiRequest(config.apiBase, `/policies/${existing.id}`, { method: "PUT", body }, config.apiKey);
47
+ return {
48
+ success: true,
49
+ policyId: existing.id,
50
+ version: updated.latestVersion || 0,
51
+ created: false,
52
+ };
53
+ }
54
+ catch (err) {
55
+ const message = err instanceof Error ? err.message : String(err);
56
+ if (message.includes("409")) {
57
+ return {
58
+ success: false,
59
+ policyId: existing.id,
60
+ version: existing.latestVersion || 0,
61
+ created: false,
62
+ error: "Policy has been modified on server. Pull latest first, or use --force.",
63
+ };
64
+ }
65
+ throw err;
66
+ }
67
+ }
68
+ else {
69
+ // Create new policy
70
+ const created = await apiRequest(config.apiBase, "/policies", {
71
+ method: "POST",
72
+ body: {
73
+ name: options.name,
74
+ description: options.description,
75
+ content: policy,
76
+ },
77
+ }, config.apiKey);
78
+ return {
79
+ success: true,
80
+ policyId: created.id || "",
81
+ version: 1,
82
+ created: true,
83
+ };
84
+ }
85
+ }
86
+ catch (err) {
87
+ return {
88
+ success: false,
89
+ policyId: "",
90
+ version: 0,
91
+ created: false,
92
+ error: err instanceof Error ? err.message : String(err),
93
+ };
94
+ }
95
+ }
96
+ /**
97
+ * Pull a policy from the server.
98
+ *
99
+ * Finds the policy by ID, name, or defaults to the default/first policy.
100
+ * Returns the full policy content for writing to a local file.
101
+ *
102
+ * @param config - API connection config
103
+ * @param options - Pull options (policyId or policyName)
104
+ * @returns Pull result with policy content and metadata
105
+ */
106
+ export async function pullPolicy(config, options) {
107
+ try {
108
+ let policyId = options.policyId;
109
+ // If no ID, find by name or get default
110
+ if (!policyId) {
111
+ const listData = await apiRequest(config.apiBase, "/policies", { method: "GET" }, config.apiKey);
112
+ if (options.policyName) {
113
+ const found = listData.policies?.find((p) => p.name === options.policyName);
114
+ if (!found) {
115
+ return {
116
+ success: false,
117
+ error: `Policy "${options.policyName}" not found on server`,
118
+ };
119
+ }
120
+ policyId = found.id;
121
+ }
122
+ else {
123
+ const defaultPolicy = listData.policies?.find((p) => p.isDefault);
124
+ const target = defaultPolicy || listData.policies?.[0];
125
+ if (!target) {
126
+ return { success: false, error: "No policies found on server" };
127
+ }
128
+ policyId = target.id;
129
+ }
130
+ }
131
+ // Fetch full policy with content
132
+ const data = await apiRequest(config.apiBase, `/policies/${policyId}`, { method: "GET" }, config.apiKey);
133
+ return {
134
+ success: true,
135
+ policy: data.content,
136
+ policyId: data.id || policyId,
137
+ version: data.latestVersion,
138
+ name: data.name,
139
+ };
140
+ }
141
+ catch (err) {
142
+ return {
143
+ success: false,
144
+ error: err instanceof Error ? err.message : String(err),
145
+ };
146
+ }
147
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Command catalog for the `suggest` command.
3
+ *
4
+ * Maps natural-language intents to exact CLI commands.
5
+ * Used for local fuzzy matching before falling back to LLM API.
6
+ */
7
+ export interface CatalogEntry {
8
+ /** Exact CLI command to run */
9
+ command: string;
10
+ /** Short explanation of what the command does */
11
+ description: string;
12
+ /** Keywords that trigger this entry */
13
+ keywords: string[];
14
+ }
15
+ /**
16
+ * Full command catalog for VertaaUX CLI.
17
+ *
18
+ * Each entry has keywords that are matched against user intent
19
+ * using simple substring/word-overlap scoring.
20
+ */
21
+ export declare const COMMAND_CATALOG: CatalogEntry[];
22
+ /**
23
+ * Score a catalog entry against user intent.
24
+ *
25
+ * Uses a combined scoring approach:
26
+ * - Each exact keyword match earns 1 point (multi-word keywords earn 2)
27
+ * - Partial word overlap earns fractional points
28
+ * - Final score = matchPoints / max(totalWeight, 3) to avoid penalizing
29
+ * entries with many keywords when only a few match.
30
+ *
31
+ * Returns a number between 0 and 1 where higher = better match.
32
+ */
33
+ export declare function scoreMatch(intent: string, entry: CatalogEntry): number;
34
+ /**
35
+ * Find the best matching command(s) for a user intent.
36
+ *
37
+ * @param intent - Natural language intent from the user
38
+ * @param threshold - Minimum score to include (0-1)
39
+ * @param maxResults - Maximum number of results to return
40
+ * @returns Sorted matches with scores
41
+ */
42
+ export declare function findMatches(intent: string, threshold?: number, maxResults?: number): Array<{
43
+ entry: CatalogEntry;
44
+ score: number;
45
+ }>;
46
+ //# sourceMappingURL=command-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-catalog.d.ts","sourceRoot":"","sources":["../../src/prompts/command-catalog.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,YAAY,EAwIzC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,MAAM,CAuBtE;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,SAAS,SAAM,EACf,UAAU,SAAI,GACb,KAAK,CAAC;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAU/C"}
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Command catalog for the `suggest` command.
3
+ *
4
+ * Maps natural-language intents to exact CLI commands.
5
+ * Used for local fuzzy matching before falling back to LLM API.
6
+ */
7
+ /**
8
+ * Full command catalog for VertaaUX CLI.
9
+ *
10
+ * Each entry has keywords that are matched against user intent
11
+ * using simple substring/word-overlap scoring.
12
+ */
13
+ export const COMMAND_CATALOG = [
14
+ // --- Audit Commands ---
15
+ {
16
+ command: "vertaa audit <url> --wait",
17
+ description: "Run a UX audit on a URL and wait for results",
18
+ keywords: ["audit", "scan", "check", "test", "run", "url", "website", "page", "site"],
19
+ },
20
+ {
21
+ command: "vertaa audit <url> --mode standard --wait",
22
+ description: "Run a standard-depth audit (more thorough than basic)",
23
+ keywords: ["standard", "thorough", "detailed", "full", "deep scan"],
24
+ },
25
+ {
26
+ command: "vertaa audit <url> --mode deep --wait",
27
+ description: "Run a deep audit with maximum coverage",
28
+ keywords: ["deep", "comprehensive", "maximum", "everything", "all checks"],
29
+ },
30
+ {
31
+ command: "vertaa audit <url> --wait --json",
32
+ description: "Run an audit and output JSON for piping to other commands",
33
+ keywords: ["json", "pipe", "machine", "ci", "scripting", "output json", "structured"],
34
+ },
35
+ {
36
+ command: "vertaa audit <url> --wait --fail-on-score 80",
37
+ description: "Run audit and fail CI if score is below 80",
38
+ keywords: ["ci", "gate", "fail", "threshold", "score", "pipeline", "quality gate"],
39
+ },
40
+ // --- Accessibility ---
41
+ {
42
+ command: "vertaa a11y <url> --wait",
43
+ description: "Run accessibility-focused audit",
44
+ keywords: ["accessibility", "a11y", "wcag", "aria", "screen reader", "accessible"],
45
+ },
46
+ {
47
+ command: "vertaa audit <url> --wait --json | vertaa explain",
48
+ description: "Audit a site and get an AI explanation of findings",
49
+ keywords: ["explain", "understand", "what", "why", "summary", "meaning"],
50
+ },
51
+ // --- Contrast & Color ---
52
+ {
53
+ command: "vertaa audit <url> --wait --json | vertaa triage",
54
+ description: "Audit and prioritize findings by severity",
55
+ keywords: ["contrast", "color", "triage", "prioritize", "priority", "important", "critical", "p0"],
56
+ },
57
+ // --- Compare ---
58
+ {
59
+ command: "vertaa compare <urlA> <urlB> --wait",
60
+ description: "Compare UX audits of two URLs",
61
+ keywords: ["compare", "diff", "versus", "vs", "difference", "before after", "regression"],
62
+ },
63
+ // --- Explain ---
64
+ {
65
+ command: "vertaa explain <finding-id> --job <job-id>",
66
+ description: "Show detailed evidence for a specific finding",
67
+ keywords: ["explain", "finding", "evidence", "detail", "issue", "specific"],
68
+ },
69
+ // --- Triage ---
70
+ {
71
+ command: "vertaa audit <url> --wait --json | vertaa triage",
72
+ description: "Prioritize audit findings into P0/P1/P2 buckets with effort estimates",
73
+ keywords: ["triage", "prioritize", "priority", "bucket", "effort", "plan", "what first"],
74
+ },
75
+ // --- Fix ---
76
+ {
77
+ command: "vertaa fix <jobId> --issue <id> --file-content \"...\"",
78
+ description: "Generate an auto-fix patch for a specific issue",
79
+ keywords: ["fix", "patch", "auto-fix", "repair", "resolve", "remediate"],
80
+ },
81
+ {
82
+ command: "vertaa fix-all <jobId> --file-content \"...\"",
83
+ description: "Generate fix patches for all issues in an audit",
84
+ keywords: ["fix all", "batch", "all issues", "bulk fix"],
85
+ },
86
+ // --- Diff ---
87
+ {
88
+ command: "vertaa diff --job-a <id> --job-b <id>",
89
+ description: "Compare two audit jobs to see what changed",
90
+ keywords: ["diff", "delta", "change", "compare jobs", "what changed"],
91
+ },
92
+ // --- Baseline ---
93
+ {
94
+ command: "vertaa baseline save",
95
+ description: "Save current audit results as a baseline for future comparison",
96
+ keywords: ["baseline", "save", "snapshot", "reference", "lock"],
97
+ },
98
+ // --- Policy ---
99
+ {
100
+ command: "vertaa policy show",
101
+ description: "Show the current audit policy configuration",
102
+ keywords: ["policy", "rules", "config", "configuration", "show policy"],
103
+ },
104
+ // --- Init & Setup ---
105
+ {
106
+ command: "vertaa init",
107
+ description: "Initialize a new VertaaUX project with configuration file",
108
+ keywords: ["init", "setup", "start", "new", "configure", "initialize", "create config"],
109
+ },
110
+ {
111
+ command: "vertaa login",
112
+ description: "Authenticate with VertaaUX API",
113
+ keywords: ["login", "auth", "authenticate", "sign in", "connect", "api key"],
114
+ },
115
+ {
116
+ command: "vertaa doctor",
117
+ description: "Run diagnostics on CLI configuration and connectivity",
118
+ keywords: ["doctor", "diagnostic", "health", "check", "debug", "troubleshoot", "problem"],
119
+ },
120
+ // --- Comment ---
121
+ {
122
+ command: "vertaa comment --job <id> --github-pr <number>",
123
+ description: "Post audit results as a GitHub PR comment",
124
+ keywords: ["comment", "pr", "pull request", "github", "gitlab", "post"],
125
+ },
126
+ // --- Upload/Download ---
127
+ {
128
+ command: "vertaa upload --file baseline.json",
129
+ description: "Upload a baseline file to the VertaaUX API",
130
+ keywords: ["upload", "push", "send"],
131
+ },
132
+ {
133
+ command: "vertaa download --job <id> --output results.json",
134
+ description: "Download audit results to a local file",
135
+ keywords: ["download", "pull", "fetch", "get", "save results"],
136
+ },
137
+ ];
138
+ /**
139
+ * Score a catalog entry against user intent.
140
+ *
141
+ * Uses a combined scoring approach:
142
+ * - Each exact keyword match earns 1 point (multi-word keywords earn 2)
143
+ * - Partial word overlap earns fractional points
144
+ * - Final score = matchPoints / max(totalWeight, 3) to avoid penalizing
145
+ * entries with many keywords when only a few match.
146
+ *
147
+ * Returns a number between 0 and 1 where higher = better match.
148
+ */
149
+ export function scoreMatch(intent, entry) {
150
+ const lower = intent.toLowerCase();
151
+ const words = lower.split(/\s+/).filter(Boolean);
152
+ let matchPoints = 0;
153
+ for (const keyword of entry.keywords) {
154
+ const kw = keyword.toLowerCase();
155
+ const weight = kw.includes(" ") ? 2 : 1;
156
+ if (lower.includes(kw)) {
157
+ matchPoints += weight;
158
+ }
159
+ else {
160
+ // Partial word overlap
161
+ const kwWords = kw.split(/\s+/);
162
+ const overlap = kwWords.filter((w) => words.includes(w)).length / kwWords.length;
163
+ matchPoints += weight * overlap * 0.5;
164
+ }
165
+ }
166
+ // Normalize: divide by a minimum of 3 so that 1 exact match = 0.33 (above threshold)
167
+ const normalizer = Math.max(entry.keywords.length, 3);
168
+ return normalizer > 0 ? Math.min(matchPoints / normalizer, 1) : 0;
169
+ }
170
+ /**
171
+ * Find the best matching command(s) for a user intent.
172
+ *
173
+ * @param intent - Natural language intent from the user
174
+ * @param threshold - Minimum score to include (0-1)
175
+ * @param maxResults - Maximum number of results to return
176
+ * @returns Sorted matches with scores
177
+ */
178
+ export function findMatches(intent, threshold = 0.1, maxResults = 3) {
179
+ const scored = COMMAND_CATALOG.map((entry) => ({
180
+ entry,
181
+ score: scoreMatch(intent, entry),
182
+ }));
183
+ return scored
184
+ .filter((m) => m.score >= threshold)
185
+ .sort((a, b) => b.score - a.score)
186
+ .slice(0, maxResults);
187
+ }
@@ -1,61 +1,36 @@
1
1
  /**
2
2
  * Progress spinner wrapper for CLI.
3
3
  *
4
- * Provides a consistent interface for showing progress during long-running operations.
5
- * Uses ora for elegant terminal spinners with TTY detection.
4
+ * Delegates to @vertaaux/tui for consistent terminal rendering.
5
+ * Writes ONLY to stderr never pollutes stdout.
6
6
  */
7
- import { type Ora } from "ora";
8
- export interface SpinnerOptions {
9
- /** Initial text to display */
10
- text: string;
11
- /** Color for the spinner (default: brand lime) */
12
- color?: string;
13
- }
7
+ import { type SpinnerInstance } from "@vertaaux/tui";
8
+ export type { SpinnerInstance };
14
9
  /**
15
10
  * Create a new spinner instance.
16
11
  *
17
12
  * Spinner only displays in TTY mode. In non-TTY environments,
18
13
  * returns a no-op spinner that still tracks state.
19
- *
20
- * @param text - Initial text to display next to spinner
21
- * @returns An ora spinner instance
22
14
  */
23
- export declare function createSpinner(text: string): Ora;
15
+ export declare function createSpinner(text: string): SpinnerInstance;
24
16
  /**
25
17
  * Update spinner text with optional progress indicator.
26
- *
27
- * @param spinner - The spinner instance to update
28
- * @param text - New text to display
29
- * @param current - Current progress count (optional)
30
- * @param total - Total items count (optional)
31
18
  */
32
- export declare function updateSpinner(spinner: Ora, text: string, current?: number, total?: number): void;
19
+ export declare function updateSpinner(spinner: SpinnerInstance, text: string, current?: number, total?: number): void;
33
20
  /**
34
21
  * Complete spinner with success state.
35
- *
36
- * @param spinner - The spinner instance
37
- * @param text - Success message to display
38
22
  */
39
- export declare function succeedSpinner(spinner: Ora, text: string): void;
23
+ export declare function succeedSpinner(spinner: SpinnerInstance, text: string): void;
40
24
  /**
41
25
  * Complete spinner with failure state.
42
- *
43
- * @param spinner - The spinner instance
44
- * @param text - Failure message to display
45
26
  */
46
- export declare function failSpinner(spinner: Ora, text: string): void;
27
+ export declare function failSpinner(spinner: SpinnerInstance, text: string): void;
47
28
  /**
48
29
  * Complete spinner with warning state.
49
- *
50
- * @param spinner - The spinner instance
51
- * @param text - Warning message to display
52
30
  */
53
- export declare function warnSpinner(spinner: Ora, text: string): void;
31
+ export declare function warnSpinner(spinner: SpinnerInstance, text: string): void;
54
32
  /**
55
33
  * Complete spinner with info state.
56
- *
57
- * @param spinner - The spinner instance
58
- * @param text - Info message to display
59
34
  */
60
- export declare function infoSpinner(spinner: Ora, text: string): void;
35
+ export declare function infoSpinner(spinner: SpinnerInstance, text: string): void;
61
36
  //# sourceMappingURL=spinner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../src/ui/spinner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAY,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AAapC,MAAM,WAAW,cAAc;IAC7B,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAiB/C;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,GAAG,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,MAAM,GACb,IAAI,CAcN;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAE/D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAE5D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAE5D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAE5D"}
1
+ {"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../src/ui/spinner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AAEvB,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAE3D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,MAAM,GACb,IAAI,CAQN;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAE3E;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAExE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAExE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAExE"}
@@ -1,101 +1,54 @@
1
1
  /**
2
2
  * Progress spinner wrapper for CLI.
3
3
  *
4
- * Provides a consistent interface for showing progress during long-running operations.
5
- * Uses ora for elegant terminal spinners with TTY detection.
4
+ * Delegates to @vertaaux/tui for consistent terminal rendering.
5
+ * Writes ONLY to stderr never pollutes stdout.
6
6
  */
7
- import ora from "ora";
8
- import chalk from "chalk";
9
- import { isTTY, shouldUseColor } from "../utils/detect-env.js";
10
- // Spinner style - classic dots for clean look
11
- const SPINNER_STYLE = {
12
- frames: ["\u2807", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"],
13
- interval: 80,
14
- };
15
- // Brand color for spinner
16
- const BRAND_COLOR = "#78FFB4";
7
+ import { createSpinner as tuiCreateSpinner, } from "@vertaaux/tui";
17
8
  /**
18
9
  * Create a new spinner instance.
19
10
  *
20
11
  * Spinner only displays in TTY mode. In non-TTY environments,
21
12
  * returns a no-op spinner that still tracks state.
22
- *
23
- * @param text - Initial text to display next to spinner
24
- * @returns An ora spinner instance
25
13
  */
26
14
  export function createSpinner(text) {
27
- const useColor = shouldUseColor();
28
- const spinner = ora({
29
- text,
30
- spinner: SPINNER_STYLE,
31
- color: "cyan",
32
- isEnabled: isTTY(),
33
- stream: process.stderr, // Write to stderr to avoid mixing with command output
34
- });
35
- // Apply brand color if colors are enabled
36
- if (useColor) {
37
- spinner.color = "cyan";
38
- }
39
- return spinner;
15
+ return tuiCreateSpinner(text);
40
16
  }
41
17
  /**
42
18
  * Update spinner text with optional progress indicator.
43
- *
44
- * @param spinner - The spinner instance to update
45
- * @param text - New text to display
46
- * @param current - Current progress count (optional)
47
- * @param total - Total items count (optional)
48
19
  */
49
20
  export function updateSpinner(spinner, text, current, total) {
50
21
  if (current !== undefined && total !== undefined) {
51
- const progress = shouldUseColor()
52
- ? chalk.dim(`(${current}/${total})`)
53
- : `(${current}/${total})`;
54
- spinner.text = `${text} ${progress}`;
22
+ spinner.setText(`${text} (${current}/${total})`);
55
23
  }
56
24
  else if (current !== undefined) {
57
- const progress = shouldUseColor()
58
- ? chalk.dim(`(${current})`)
59
- : `(${current})`;
60
- spinner.text = `${text} ${progress}`;
25
+ spinner.setText(`${text} (${current})`);
61
26
  }
62
27
  else {
63
- spinner.text = text;
28
+ spinner.setText(text);
64
29
  }
65
30
  }
66
31
  /**
67
32
  * Complete spinner with success state.
68
- *
69
- * @param spinner - The spinner instance
70
- * @param text - Success message to display
71
33
  */
72
34
  export function succeedSpinner(spinner, text) {
73
- spinner.succeed(shouldUseColor() ? chalk.green(text) : text);
35
+ spinner.succeed(text);
74
36
  }
75
37
  /**
76
38
  * Complete spinner with failure state.
77
- *
78
- * @param spinner - The spinner instance
79
- * @param text - Failure message to display
80
39
  */
81
40
  export function failSpinner(spinner, text) {
82
- spinner.fail(shouldUseColor() ? chalk.red(text) : text);
41
+ spinner.fail(text);
83
42
  }
84
43
  /**
85
44
  * Complete spinner with warning state.
86
- *
87
- * @param spinner - The spinner instance
88
- * @param text - Warning message to display
89
45
  */
90
46
  export function warnSpinner(spinner, text) {
91
- spinner.warn(shouldUseColor() ? chalk.yellow(text) : text);
47
+ spinner.warn(text);
92
48
  }
93
49
  /**
94
50
  * Complete spinner with info state.
95
- *
96
- * @param spinner - The spinner instance
97
- * @param text - Info message to display
98
51
  */
99
52
  export function infoSpinner(spinner, text) {
100
- spinner.info(shouldUseColor() ? chalk.cyan(text) : text);
53
+ spinner.info(text);
101
54
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Table formatting utilities for CLI output.
3
3
  *
4
- * Uses cli-table3 for clean table rendering with severity-based coloring.
4
+ * Delegates to @vertaaux/tui for consistent rendering with severity-based coloring.
5
5
  * Respects terminal width and provides truncation for long content.
6
6
  */
7
7
  export interface Issue {
@@ -33,31 +33,14 @@ export declare function groupBySeverity(issues: Issue[]): Map<string, Issue[]>;
33
33
  export declare function groupByCategory(issues: Issue[]): Map<string, Issue[]>;
34
34
  /**
35
35
  * Format issues into a table string.
36
- *
37
- * Columns: Severity | ID | Description | Selector (optional)
38
- * Issues are sorted by severity (critical -> info).
39
- *
40
- * @param issues - Array of issues to format
41
- * @param options - Formatting options
42
- * @returns Formatted table string
43
36
  */
44
37
  export declare function formatIssuesTable(issues: Issue[], options?: FormatTableOptions): string;
45
- export interface Score {
46
- category: string;
47
- score: number;
48
- }
49
38
  /**
50
39
  * Format scores into a table string.
51
- *
52
- * @param scores - Object mapping category names to scores
53
- * @returns Formatted table string
54
40
  */
55
41
  export declare function formatScoresTable(scores: Record<string, number | unknown>): string;
56
42
  /**
57
43
  * Format a summary line showing issue counts by severity.
58
- *
59
- * @param issues - Array of issues
60
- * @returns Summary string like "3 critical, 5 serious, 12 minor issues"
61
44
  */
62
45
  export declare function formatIssueSummary(issues: Issue[]): string;
63
46
  //# sourceMappingURL=table.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../src/ui/table.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAuCH,MAAM,WAAW,KAAK;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,2CAA2C;IAC3C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wCAAwC;IACxC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0CAA0C;IAC1C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAqCD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAWrE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAWrE;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,KAAK,EAAE,EACf,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CAoER;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,MAAM,CAyClF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAkC1D"}
1
+ {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../src/ui/table.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAeH,MAAM,WAAW,KAAK;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,2CAA2C;IAC3C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wCAAwC;IACxC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0CAA0C;IAC1C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAaD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CASrE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CASrE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,KAAK,EAAE,EACf,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CAuCR;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,MAAM,CA2BlF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CA4B1D"}