ghagga 2.4.1 → 2.6.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 (62) hide show
  1. package/README.md +48 -8
  2. package/dist/commands/__tests__/review-tui.test.d.ts +11 -0
  3. package/dist/commands/__tests__/review-tui.test.d.ts.map +1 -0
  4. package/dist/commands/__tests__/review-tui.test.js +256 -0
  5. package/dist/commands/__tests__/review-tui.test.js.map +1 -0
  6. package/dist/commands/health.d.ts +16 -0
  7. package/dist/commands/health.d.ts.map +1 -0
  8. package/dist/commands/health.js +139 -0
  9. package/dist/commands/health.js.map +1 -0
  10. package/dist/commands/review-output.test.d.ts +10 -0
  11. package/dist/commands/review-output.test.d.ts.map +1 -0
  12. package/dist/commands/review-output.test.js +222 -0
  13. package/dist/commands/review-output.test.js.map +1 -0
  14. package/dist/commands/review.d.ts +8 -1
  15. package/dist/commands/review.d.ts.map +1 -1
  16. package/dist/commands/review.js +139 -22
  17. package/dist/commands/review.js.map +1 -1
  18. package/dist/commands/review.test.js +29 -11
  19. package/dist/commands/review.test.js.map +1 -1
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.js +45 -9
  22. package/dist/index.js.map +1 -1
  23. package/dist/lib/github-api.d.ts +69 -0
  24. package/dist/lib/github-api.d.ts.map +1 -0
  25. package/dist/lib/github-api.js +186 -0
  26. package/dist/lib/github-api.js.map +1 -0
  27. package/dist/lib/github-api.test.d.ts +2 -0
  28. package/dist/lib/github-api.test.d.ts.map +1 -0
  29. package/dist/lib/github-api.test.js +197 -0
  30. package/dist/lib/github-api.test.js.map +1 -0
  31. package/dist/lib/oauth.d.ts +2 -2
  32. package/dist/lib/oauth.d.ts.map +1 -1
  33. package/dist/lib/oauth.js +2 -2
  34. package/dist/lib/oauth.js.map +1 -1
  35. package/dist/lib/oauth.test.js +1 -1
  36. package/dist/lib/oauth.test.js.map +1 -1
  37. package/dist/ui/__tests__/tui-extensions.test.d.ts +9 -0
  38. package/dist/ui/__tests__/tui-extensions.test.d.ts.map +1 -0
  39. package/dist/ui/__tests__/tui-extensions.test.js +230 -0
  40. package/dist/ui/__tests__/tui-extensions.test.js.map +1 -0
  41. package/dist/ui/chalk.d.ts +17 -0
  42. package/dist/ui/chalk.d.ts.map +1 -0
  43. package/dist/ui/chalk.js +25 -0
  44. package/dist/ui/chalk.js.map +1 -0
  45. package/dist/ui/format.d.ts +21 -1
  46. package/dist/ui/format.d.ts.map +1 -1
  47. package/dist/ui/format.js +67 -1
  48. package/dist/ui/format.js.map +1 -1
  49. package/dist/ui/sarif.d.ts +6 -0
  50. package/dist/ui/sarif.d.ts.map +1 -0
  51. package/dist/ui/sarif.js +5 -0
  52. package/dist/ui/sarif.js.map +1 -0
  53. package/dist/ui/theme.d.ts +16 -0
  54. package/dist/ui/theme.d.ts.map +1 -1
  55. package/dist/ui/theme.js +16 -0
  56. package/dist/ui/theme.js.map +1 -1
  57. package/dist/ui/tui.d.ts +31 -0
  58. package/dist/ui/tui.d.ts.map +1 -1
  59. package/dist/ui/tui.js +91 -0
  60. package/dist/ui/tui.js.map +1 -1
  61. package/package.json +17 -15
  62. package/LICENSE +0 -21
package/README.md CHANGED
@@ -17,7 +17,7 @@ GHAGGA is a multi-agent AI code reviewer that analyzes your code changes using L
17
17
  |------|-------|-------|-----------|
18
18
  | **simple** | ~2s | Single-pass review | 1 |
19
19
  | **workflow** | ~15s | 5 specialist agents + synthesis | 6 |
20
- | **consensus** | ~7s | For/against/neutral voting | 3 |
20
+ | **consensus** | ~7s | Same model, three perspectives + algorithmic vote | 3 |
21
21
 
22
22
  ## Quick Start
23
23
 
@@ -100,11 +100,13 @@ Options:
100
100
  -p, --provider <provider> LLM provider: github, anthropic, openai, google, ollama, qwen
101
101
  --model <model> LLM model identifier
102
102
  --api-key <key> LLM provider API key
103
- -f, --format <format> Output format: markdown, json (default: "markdown")
103
+ -o, --output <format> Output format: markdown, json, sarif (default: "markdown")
104
+ --enhance AI-powered post-analysis enhancement (groups findings, adds fix suggestions)
105
+ --issue <target> Create (new) or update (<number>) a GitHub issue with review results
104
106
  -v, --verbose Show detailed progress during review
105
- --no-semgrep Disable Semgrep static analysis
106
- --no-trivy Disable Trivy vulnerability scanning
107
- --no-cpd Disable CPD duplicate detection
107
+ --enable-tool <name> Force-enable a specific tool (can be repeated)
108
+ --disable-tool <name> Force-disable a specific tool (can be repeated)
109
+ --list-tools Show all 15 available tools with status
108
110
  --no-memory Disable review memory (skip search and persist)
109
111
  --memory-backend <type> Memory backend: sqlite (default) or engram
110
112
  --staged Review only staged files (for pre-commit hook)
@@ -142,6 +144,43 @@ ghagga memory clear [--repo <owner/repo>] [--force]
142
144
 
143
145
  Memory is stored locally at `~/.config/ghagga/memory.db` (SQLite + FTS5). Observations are automatically extracted from reviews and used to provide context in future reviews.
144
146
 
147
+ ### Deprecated Flags
148
+
149
+ The following flags still work but show deprecation warnings:
150
+
151
+ ```
152
+ -f, --format <format> Use --output instead
153
+ --no-semgrep Use --disable-tool semgrep instead
154
+ --no-trivy Use --disable-tool trivy instead
155
+ --no-cpd Use --disable-tool cpd instead
156
+ ```
157
+
158
+ ## Health Command
159
+
160
+ Run a project health assessment with scoring, historical trends, and actionable recommendations:
161
+
162
+ ```bash
163
+ # Basic health check
164
+ ghagga health
165
+
166
+ # Health check on a specific path
167
+ ghagga health ./src
168
+
169
+ # Show top 10 issues
170
+ ghagga health --top 10
171
+
172
+ # JSON output for CI integration
173
+ ghagga health --output json
174
+ ```
175
+
176
+ Options:
177
+
178
+ | Option | Default | Description |
179
+ |--------|---------|-------------|
180
+ | `[path]` | `.` | Path to repository or subdirectory |
181
+ | `--top <n>` | `5` | Number of top issues to display |
182
+ | `--output <format>` | `markdown` | Output format (inherits global `--output`) |
183
+
145
184
  ## BYOK (Bring Your Own Key)
146
185
 
147
186
  Use any supported LLM provider:
@@ -204,14 +243,15 @@ Create a `.ghagga.json` in your project root:
204
243
  ```json
205
244
  {
206
245
  "mode": "workflow",
207
- "enableSemgrep": true,
208
- "enableTrivy": true,
209
- "enableCpd": true,
246
+ "enabledTools": ["ruff", "bandit"],
247
+ "disabledTools": ["markdownlint"],
210
248
  "ignorePatterns": ["*.test.ts", "*.spec.ts"],
211
249
  "reviewLevel": "strict"
212
250
  }
213
251
  ```
214
252
 
253
+ > The legacy fields `enableSemgrep`, `enableTrivy`, `enableCpd` still work but are deprecated. Use `enabledTools`/`disabledTools` arrays instead.
254
+
215
255
  ## How It Works
216
256
 
217
257
  1. Gets your `git diff` (staged or uncommitted changes; `--staged` uses `git diff --cached`)
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Tests for TUI-polished review output.
3
+ *
4
+ * Validates formatBoxSummary, formatToolDivider, and formatMarkdownResult
5
+ * from ui/format.ts — the pure functions behind the review command's
6
+ * box summary, tool section dividers, and markdown output.
7
+ *
8
+ * All functions are pure (string in, string out) — no mocking needed.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=review-tui.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-tui.test.d.ts","sourceRoot":"","sources":["../../../src/commands/__tests__/review-tui.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Tests for TUI-polished review output.
3
+ *
4
+ * Validates formatBoxSummary, formatToolDivider, and formatMarkdownResult
5
+ * from ui/format.ts — the pure functions behind the review command's
6
+ * box summary, tool section dividers, and markdown output.
7
+ *
8
+ * All functions are pure (string in, string out) — no mocking needed.
9
+ */
10
+ import { describe, expect, it } from 'vitest';
11
+ import { formatBoxSummary, formatMarkdownResult, formatToolDivider } from '../../ui/format.js';
12
+ // ─── Helpers ────────────────────────────────────────────────────
13
+ function mockResult(overrides) {
14
+ return {
15
+ status: 'PASSED',
16
+ summary: 'All good',
17
+ findings: [],
18
+ staticAnalysis: {
19
+ semgrep: { status: 'skipped', findings: [], executionTimeMs: 0 },
20
+ trivy: { status: 'skipped', findings: [], executionTimeMs: 0 },
21
+ cpd: { status: 'skipped', findings: [], executionTimeMs: 0 },
22
+ },
23
+ memoryContext: null,
24
+ metadata: {
25
+ mode: 'simple',
26
+ model: 'gpt-4o-mini',
27
+ provider: 'github',
28
+ executionTimeMs: 2500,
29
+ tokensUsed: 150,
30
+ toolsRun: ['semgrep', 'trivy'],
31
+ toolsSkipped: ['cpd'],
32
+ },
33
+ ...overrides,
34
+ };
35
+ }
36
+ // ─── formatBoxSummary ───────────────────────────────────────────
37
+ describe('formatBoxSummary', () => {
38
+ it('includes status, time, mode, and model', () => {
39
+ const lines = formatBoxSummary(mockResult());
40
+ const text = lines.join('\n');
41
+ expect(text).toContain('PASSED');
42
+ expect(text).toContain('2.5s');
43
+ expect(text).toContain('simple');
44
+ expect(text).toContain('gpt-4o-mini');
45
+ });
46
+ it('shows finding counts by severity', () => {
47
+ const result = mockResult({
48
+ findings: [
49
+ { file: 'a.ts', severity: 'critical', category: 'sec', message: 'bad', source: 'semgrep' },
50
+ { file: 'b.ts', severity: 'high', category: 'sec', message: 'bad', source: 'semgrep' },
51
+ { file: 'c.ts', severity: 'medium', category: 'quality', message: 'meh', source: 'trivy' },
52
+ ],
53
+ });
54
+ const lines = formatBoxSummary(result);
55
+ const text = lines.join('\n');
56
+ expect(text).toContain('3 total');
57
+ expect(text).toContain('critical');
58
+ expect(text).toContain('high');
59
+ expect(text).toContain('medium');
60
+ });
61
+ it('shows clean message when no findings', () => {
62
+ const lines = formatBoxSummary(mockResult());
63
+ const text = lines.join('\n');
64
+ expect(text).toContain('0');
65
+ expect(text).toContain('clean');
66
+ });
67
+ it('lists tools run', () => {
68
+ const lines = formatBoxSummary(mockResult());
69
+ const text = lines.join('\n');
70
+ expect(text).toContain('semgrep');
71
+ expect(text).toContain('trivy');
72
+ });
73
+ it('includes token count', () => {
74
+ const lines = formatBoxSummary(mockResult());
75
+ const text = lines.join('\n');
76
+ expect(text).toContain('150');
77
+ });
78
+ it('does not show tools line when no tools ran', () => {
79
+ const result = mockResult({
80
+ metadata: {
81
+ mode: 'simple',
82
+ model: 'gpt-4o-mini',
83
+ provider: 'github',
84
+ executionTimeMs: 1000,
85
+ tokensUsed: 50,
86
+ toolsRun: [],
87
+ toolsSkipped: [],
88
+ },
89
+ });
90
+ const lines = formatBoxSummary(result);
91
+ const text = lines.join('\n');
92
+ expect(text).not.toContain('Tools:');
93
+ });
94
+ it('shows all five severity levels when present', () => {
95
+ const result = mockResult({
96
+ findings: [
97
+ { file: 'a.ts', severity: 'critical', category: 'sec', message: 'x', source: 'ai' },
98
+ { file: 'b.ts', severity: 'high', category: 'sec', message: 'x', source: 'ai' },
99
+ { file: 'c.ts', severity: 'medium', category: 'sec', message: 'x', source: 'ai' },
100
+ { file: 'd.ts', severity: 'low', category: 'sec', message: 'x', source: 'ai' },
101
+ { file: 'e.ts', severity: 'info', category: 'sec', message: 'x', source: 'ai' },
102
+ ],
103
+ });
104
+ const lines = formatBoxSummary(result);
105
+ const text = lines.join('\n');
106
+ expect(text).toContain('5 total');
107
+ expect(text).toContain('critical');
108
+ expect(text).toContain('high');
109
+ expect(text).toContain('medium');
110
+ expect(text).toContain('low');
111
+ expect(text).toContain('info');
112
+ });
113
+ it('formats FAILED status correctly', () => {
114
+ const result = mockResult({ status: 'FAILED' });
115
+ const lines = formatBoxSummary(result);
116
+ const text = lines.join('\n');
117
+ expect(text).toContain('FAILED');
118
+ });
119
+ });
120
+ // ─── formatToolDivider ──────────────────────────────────────────
121
+ describe('formatToolDivider', () => {
122
+ it('contains the label and dash characters', () => {
123
+ const divider = formatToolDivider('Semgrep (3)');
124
+ expect(divider).toContain('Semgrep (3)');
125
+ expect(divider).toContain('─');
126
+ });
127
+ it('has consistent structure with ─── prefix before label', () => {
128
+ const divider = formatToolDivider('Trivy');
129
+ expect(divider).toMatch(/─── Trivy ─+$/);
130
+ });
131
+ it('pads to consistent width with trailing dashes', () => {
132
+ const short = formatToolDivider('A');
133
+ const long = formatToolDivider('A longer label here');
134
+ // Both should contain the ─── prefix pattern
135
+ expect(short).toContain('─── A ');
136
+ expect(long).toContain('─── A longer label here ');
137
+ // Short label gets more trailing dashes
138
+ const shortDashCount = (short.match(/─/g) ?? []).length;
139
+ const longDashCount = (long.match(/─/g) ?? []).length;
140
+ expect(shortDashCount).toBeGreaterThan(longDashCount);
141
+ });
142
+ it('starts with a newline for visual separation', () => {
143
+ const divider = formatToolDivider('Test');
144
+ expect(divider.startsWith('\n')).toBe(true);
145
+ });
146
+ it('handles empty label gracefully', () => {
147
+ const divider = formatToolDivider('');
148
+ expect(divider).toContain('─');
149
+ });
150
+ });
151
+ // ─── formatMarkdownResult ───────────────────────────────────────
152
+ describe('formatMarkdownResult', () => {
153
+ it('contains tool dividers when findings from multiple sources', () => {
154
+ const result = mockResult({
155
+ findings: [
156
+ { file: 'a.ts', severity: 'high', category: 'sec', message: 'issue1', source: 'semgrep' },
157
+ { file: 'b.ts', severity: 'medium', category: 'vuln', message: 'issue2', source: 'trivy' },
158
+ ],
159
+ });
160
+ const output = formatMarkdownResult(result);
161
+ // Uses ─ tool dividers (not markdown ### headings)
162
+ expect(output).toContain('─');
163
+ // Both tool labels should appear
164
+ expect(output).toContain('Semgrep');
165
+ expect(output).toContain('Trivy');
166
+ });
167
+ it('shows no findings message when findings are empty', () => {
168
+ const output = formatMarkdownResult(mockResult());
169
+ expect(output).toContain('No findings');
170
+ });
171
+ it('includes header with status and review branding', () => {
172
+ const output = formatMarkdownResult(mockResult());
173
+ expect(output).toContain('GHAGGA Code Review');
174
+ expect(output).toContain('PASSED');
175
+ });
176
+ it('includes execution metadata', () => {
177
+ const output = formatMarkdownResult(mockResult());
178
+ expect(output).toContain('Mode: simple');
179
+ expect(output).toContain('Model: gpt-4o-mini');
180
+ expect(output).toContain('2.5s');
181
+ expect(output).toContain('150');
182
+ });
183
+ it('renders findings with severity, category, and message', () => {
184
+ const result = mockResult({
185
+ findings: [
186
+ {
187
+ file: 'src/app.ts',
188
+ line: 42,
189
+ severity: 'critical',
190
+ category: 'security',
191
+ message: 'SQL injection vulnerability',
192
+ source: 'semgrep',
193
+ },
194
+ ],
195
+ });
196
+ const output = formatMarkdownResult(result);
197
+ expect(output).toContain('CRITICAL');
198
+ expect(output).toContain('security');
199
+ expect(output).toContain('SQL injection vulnerability');
200
+ expect(output).toContain('src/app.ts:42');
201
+ });
202
+ it('renders suggestions when present', () => {
203
+ const result = mockResult({
204
+ findings: [
205
+ {
206
+ file: 'x.ts',
207
+ severity: 'medium',
208
+ category: 'perf',
209
+ message: 'Slow query',
210
+ suggestion: 'Add an index',
211
+ source: 'ai',
212
+ },
213
+ ],
214
+ });
215
+ const output = formatMarkdownResult(result);
216
+ expect(output).toContain('Add an index');
217
+ });
218
+ it('orders semgrep before trivy before ai findings', () => {
219
+ const result = mockResult({
220
+ findings: [
221
+ { file: 'a.ts', severity: 'high', category: 'sec', message: 'ai issue', source: 'ai' },
222
+ {
223
+ file: 'b.ts',
224
+ severity: 'medium',
225
+ category: 'sec',
226
+ message: 'trivy issue',
227
+ source: 'trivy',
228
+ },
229
+ {
230
+ file: 'c.ts',
231
+ severity: 'low',
232
+ category: 'sec',
233
+ message: 'semgrep issue',
234
+ source: 'semgrep',
235
+ },
236
+ ],
237
+ });
238
+ const output = formatMarkdownResult(result);
239
+ const semgrepIdx = output.indexOf('Semgrep');
240
+ const trivyIdx = output.indexOf('Trivy');
241
+ const aiIdx = output.indexOf('AI Review');
242
+ expect(semgrepIdx).toBeLessThan(trivyIdx);
243
+ expect(trivyIdx).toBeLessThan(aiIdx);
244
+ });
245
+ it('includes static analysis section when tools ran', () => {
246
+ const output = formatMarkdownResult(mockResult());
247
+ expect(output).toContain('Static Analysis');
248
+ expect(output).toContain('semgrep, trivy');
249
+ expect(output).toContain('cpd');
250
+ });
251
+ it('includes the powered-by footer', () => {
252
+ const output = formatMarkdownResult(mockResult());
253
+ expect(output).toContain('Powered by GHAGGA');
254
+ });
255
+ });
256
+ //# sourceMappingURL=review-tui.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-tui.test.js","sourceRoot":"","sources":["../../../src/commands/__tests__/review-tui.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Health command — quick project health check with scoring and trends.
3
+ *
4
+ * Does NOT require authentication. Runs always-on static analysis
5
+ * tools locally and computes a health score with trends.
6
+ */
7
+ export interface HealthOptions {
8
+ /** Output format: 'json' or default (styled TUI). */
9
+ output?: string;
10
+ /** Plain mode. */
11
+ plain?: boolean;
12
+ /** Number of top issues to show (default: 5). */
13
+ top?: number;
14
+ }
15
+ export declare function healthCommand(targetPath: string, options: HealthOptions): Promise<void>;
16
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/commands/health.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwBH,MAAM,WAAW,aAAa;IAC5B,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iDAAiD;IACjD,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAaD,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA+F7F"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Health command — quick project health check with scoring and trends.
3
+ *
4
+ * Does NOT require authentication. Runs always-on static analysis
5
+ * tools locally and computes a health score with trends.
6
+ */
7
+ import { resolve } from 'node:path';
8
+ import { computeHealthScore, computeTrend, createNodeExecutionContext, formatTopIssues, generateRecommendations, initializeDefaultTools, loadHistory, resolveActivatedTools, runTools, saveHistory, toolRegistry, } from 'ghagga-core';
9
+ import { getConfigDir } from '../lib/config.js';
10
+ import { resolveProjectId } from '../lib/git.js';
11
+ import { formatHealthScore, formatSeverityLine } from '../ui/format.js';
12
+ import * as tui from '../ui/tui.js';
13
+ // ─── Constants ──────────────────────────────────────────────────
14
+ /** Direction arrows for trend display. */
15
+ const TREND_ARROWS = {
16
+ up: '↑',
17
+ down: '↓',
18
+ unchanged: '→',
19
+ };
20
+ // ─── Main Command ───────────────────────────────────────────────
21
+ export async function healthCommand(targetPath, options) {
22
+ const repoPath = resolve(targetPath);
23
+ const top = options.top ?? 5;
24
+ try {
25
+ // Step 1: Initialize tool registry
26
+ initializeDefaultTools();
27
+ if (!options.output) {
28
+ tui.intro('šŸ„ GHAGGA Health Check');
29
+ }
30
+ // Step 2: Run static analysis (always-on tools only)
31
+ if (!options.output) {
32
+ tui.log.step('Running static analysis...');
33
+ }
34
+ const alwaysOnTools = resolveActivatedTools({
35
+ registry: toolRegistry,
36
+ files: [],
37
+ enabledTools: toolRegistry
38
+ .getAll()
39
+ .filter((t) => t.tier === 'always-on')
40
+ .map((t) => t.name),
41
+ });
42
+ const ctx = createNodeExecutionContext();
43
+ const staticResult = await runTools(ctx, alwaysOnTools, repoPath, []);
44
+ // Step 3: Collect all findings
45
+ const allFindings = [];
46
+ const toolsRun = [];
47
+ for (const [toolName, toolResult] of Object.entries(staticResult)) {
48
+ if (toolResult.status === 'success' || toolResult.status === 'error') {
49
+ toolsRun.push(toolName);
50
+ }
51
+ allFindings.push(...toolResult.findings);
52
+ }
53
+ // Step 4: Compute health score
54
+ const healthScore = computeHealthScore(allFindings);
55
+ // Step 5: Load history and compute trend
56
+ const projectPath = resolveProjectId(repoPath);
57
+ const configDir = getConfigDir();
58
+ const history = loadHistory(configDir, projectPath);
59
+ const trend = computeTrend(healthScore.score, history);
60
+ // Step 6: Generate recommendations
61
+ const recommendations = generateRecommendations(allFindings, top);
62
+ // Step 7: Get top issues
63
+ const topIssues = formatTopIssues(allFindings, top);
64
+ // Step 8: Output
65
+ if (options.output === 'json') {
66
+ const result = {
67
+ score: healthScore,
68
+ trend,
69
+ recommendations,
70
+ topIssues: topIssues.map((f) => ({
71
+ file: f.file,
72
+ line: f.line,
73
+ severity: f.severity,
74
+ category: f.category,
75
+ message: f.message,
76
+ source: f.source,
77
+ })),
78
+ toolsRun,
79
+ timestamp: new Date().toISOString(),
80
+ };
81
+ console.log(JSON.stringify(result, null, 2));
82
+ }
83
+ else {
84
+ renderStyledOutput(healthScore, trend, topIssues, recommendations, toolsRun);
85
+ }
86
+ // Step 9: Save history
87
+ const entry = {
88
+ timestamp: new Date().toISOString(),
89
+ score: healthScore.score,
90
+ findingCounts: { ...healthScore.findingCounts },
91
+ toolsRun,
92
+ projectPath,
93
+ };
94
+ saveHistory(configDir, entry);
95
+ if (!options.output) {
96
+ tui.outro('Health check complete');
97
+ }
98
+ }
99
+ catch (error) {
100
+ const message = error instanceof Error ? error.message : String(error);
101
+ tui.log.error(`\nāŒ Health check failed: ${message}`);
102
+ process.exit(1);
103
+ }
104
+ }
105
+ // ─── Styled Output ──────────────────────────────────────────────
106
+ function renderStyledOutput(healthScore, trend, topIssues, recommendations, toolsRun) {
107
+ // Score box
108
+ const scoreLines = formatHealthScore(healthScore.score, healthScore.grade);
109
+ // Add trend info
110
+ if (trend.direction) {
111
+ const arrow = TREND_ARROWS[trend.direction] ?? '';
112
+ const deltaStr = trend.delta !== null ? (trend.delta > 0 ? `+${trend.delta}` : String(trend.delta)) : '';
113
+ scoreLines.push(`Trend: ${arrow} ${deltaStr} (previous: ${trend.previous})`);
114
+ }
115
+ else {
116
+ scoreLines.push('Trend: First run — no history yet');
117
+ }
118
+ scoreLines.push('');
119
+ scoreLines.push(`Tools: ${toolsRun.join(', ')}`);
120
+ tui.log.message(tui.box('Health Score', scoreLines));
121
+ // Top issues
122
+ if (topIssues.length > 0) {
123
+ tui.log.message('');
124
+ tui.log.message(tui.divider('Top Issues'));
125
+ for (const issue of topIssues) {
126
+ tui.log.message(` ${formatSeverityLine(issue)}`);
127
+ }
128
+ }
129
+ // Recommendations
130
+ if (recommendations.length > 0) {
131
+ tui.log.message('');
132
+ tui.log.message(tui.divider('Recommendations'));
133
+ for (const rec of recommendations) {
134
+ const impact = rec.impact === 'high' ? 'šŸ”“' : rec.impact === 'medium' ? '🟔' : '🟢';
135
+ tui.log.message(` ${impact} [${rec.category}] ${rec.action}`);
136
+ }
137
+ }
138
+ }
139
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/commands/health.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,0BAA0B,EAC1B,eAAe,EACf,uBAAuB,EACvB,sBAAsB,EACtB,WAAW,EACX,qBAAqB,EACrB,QAAQ,EACR,WAAW,EACX,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AAapC,mEAAmE;AAEnE,0CAA0C;AAC1C,MAAM,YAAY,GAA2B;IAC3C,EAAE,EAAE,GAAG;IACP,IAAI,EAAE,GAAG;IACT,SAAS,EAAE,GAAG;CACf,CAAC;AAEF,mEAAmE;AAEnE,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAkB,EAAE,OAAsB;IAC5E,MAAM,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACrC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;IAE7B,IAAI,CAAC;QACH,mCAAmC;QACnC,sBAAsB,EAAE,CAAC;QAEzB,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,GAAG,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACtC,CAAC;QAED,qDAAqD;QACrD,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,aAAa,GAAG,qBAAqB,CAAC;YAC1C,QAAQ,EAAE,YAAY;YACtB,KAAK,EAAE,EAAE;YACT,YAAY,EAAE,YAAY;iBACvB,MAAM,EAAE;iBACR,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC;iBACrC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SACtB,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,0BAA0B,EAAE,CAAC;QACzC,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;QAEtE,+BAA+B;QAC/B,MAAM,WAAW,GAAoB,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,KAAK,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;YAClE,IAAI,UAAU,CAAC,MAAM,KAAK,SAAS,IAAI,UAAU,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;gBACrE,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC1B,CAAC;YACD,WAAW,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC3C,CAAC;QAED,+BAA+B;QAC/B,MAAM,WAAW,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;QAEpD,yCAAyC;QACzC,MAAM,WAAW,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QACpD,MAAM,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAEvD,mCAAmC;QACnC,MAAM,eAAe,GAAG,uBAAuB,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QAElE,yBAAyB;QACzB,MAAM,SAAS,GAAG,eAAe,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QAEpD,iBAAiB;QACjB,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG;gBACb,KAAK,EAAE,WAAW;gBAClB,KAAK;gBACL,eAAe;gBACf,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBAC/B,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;oBACpB,QAAQ,EAAE,CAAC,CAAC,QAAQ;oBACpB,OAAO,EAAE,CAAC,CAAC,OAAO;oBAClB,MAAM,EAAE,CAAC,CAAC,MAAM;iBACjB,CAAC,CAAC;gBACH,QAAQ;gBACR,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;YACF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/C,CAAC;aAAM,CAAC;YACN,kBAAkB,CAAC,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,QAAQ,CAAC,CAAC;QAC/E,CAAC;QAED,uBAAuB;QACvB,MAAM,KAAK,GAAuB;YAChC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,KAAK,EAAE,WAAW,CAAC,KAAK;YACxB,aAAa,EAAE,EAAE,GAAG,WAAW,CAAC,aAAa,EAAE;YAC/C,QAAQ;YACR,WAAW;SACZ,CAAC;QACF,WAAW,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAE9B,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,GAAG,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,4BAA4B,OAAO,EAAE,CAAC,CAAC;QACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,mEAAmE;AAEnE,SAAS,kBAAkB,CACzB,WAAkD,EAClD,KAAsC,EACtC,SAA0B,EAC1B,eAA2D,EAC3D,QAAkB;IAElB,YAAY;IACZ,MAAM,UAAU,GAAG,iBAAiB,CAAC,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;IAE3E,iBAAiB;IACjB,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAClD,MAAM,QAAQ,GACZ,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1F,UAAU,CAAC,IAAI,CAAC,UAAU,KAAK,IAAI,QAAQ,eAAe,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;IAC/E,CAAC;SAAM,CAAC;QACN,UAAU,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IAED,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpB,UAAU,CAAC,IAAI,CAAC,UAAU,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEjD,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC,CAAC;IAErD,aAAa;IACb,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;QAC3C,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;YAC9B,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED,kBAAkB;IAClB,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC;QAChD,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;YAClC,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YACpF,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,MAAM,KAAK,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Output format routing tests for the review command.
3
+ *
4
+ * Tests that --output json / sarif / markdown produce correct output
5
+ * and that TUI decorations are suppressed when --output is set.
6
+ *
7
+ * Uses the same mock patterns as review.test.ts.
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=review-output.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-output.test.d.ts","sourceRoot":"","sources":["../../src/commands/review-output.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}