ghagga 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +41 -8
  2. package/dist/commands/hooks/index.d.ts +9 -0
  3. package/dist/commands/hooks/index.d.ts.map +1 -0
  4. package/dist/commands/hooks/index.js +16 -0
  5. package/dist/commands/hooks/index.js.map +1 -0
  6. package/dist/commands/hooks/install.d.ts +13 -0
  7. package/dist/commands/hooks/install.d.ts.map +1 -0
  8. package/dist/commands/hooks/install.js +64 -0
  9. package/dist/commands/hooks/install.js.map +1 -0
  10. package/dist/commands/hooks/install.test.d.ts +11 -0
  11. package/dist/commands/hooks/install.test.d.ts.map +1 -0
  12. package/dist/commands/hooks/install.test.js +157 -0
  13. package/dist/commands/hooks/install.test.js.map +1 -0
  14. package/dist/commands/hooks/status.d.ts +12 -0
  15. package/dist/commands/hooks/status.d.ts.map +1 -0
  16. package/dist/commands/hooks/status.js +38 -0
  17. package/dist/commands/hooks/status.js.map +1 -0
  18. package/dist/commands/hooks/status.test.d.ts +11 -0
  19. package/dist/commands/hooks/status.test.d.ts.map +1 -0
  20. package/dist/commands/hooks/status.test.js +123 -0
  21. package/dist/commands/hooks/status.test.js.map +1 -0
  22. package/dist/commands/hooks/uninstall.d.ts +12 -0
  23. package/dist/commands/hooks/uninstall.d.ts.map +1 -0
  24. package/dist/commands/hooks/uninstall.js +44 -0
  25. package/dist/commands/hooks/uninstall.js.map +1 -0
  26. package/dist/commands/hooks/uninstall.test.d.ts +10 -0
  27. package/dist/commands/hooks/uninstall.test.d.ts.map +1 -0
  28. package/dist/commands/hooks/uninstall.test.js +120 -0
  29. package/dist/commands/hooks/uninstall.test.js.map +1 -0
  30. package/dist/commands/review-commit-msg.d.ts +28 -0
  31. package/dist/commands/review-commit-msg.d.ts.map +1 -0
  32. package/dist/commands/review-commit-msg.js +126 -0
  33. package/dist/commands/review-commit-msg.js.map +1 -0
  34. package/dist/commands/review-commit-msg.test.d.ts +11 -0
  35. package/dist/commands/review-commit-msg.test.d.ts.map +1 -0
  36. package/dist/commands/review-commit-msg.test.js +126 -0
  37. package/dist/commands/review-commit-msg.test.js.map +1 -0
  38. package/dist/commands/review.d.ts +6 -0
  39. package/dist/commands/review.d.ts.map +1 -1
  40. package/dist/commands/review.js +105 -10
  41. package/dist/commands/review.js.map +1 -1
  42. package/dist/index.d.ts +5 -4
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +21 -7
  45. package/dist/index.js.map +1 -1
  46. package/dist/lib/git-hooks.d.ts +19 -0
  47. package/dist/lib/git-hooks.d.ts.map +1 -0
  48. package/dist/lib/git-hooks.js +129 -0
  49. package/dist/lib/git-hooks.js.map +1 -0
  50. package/dist/lib/git-hooks.test.d.ts +11 -0
  51. package/dist/lib/git-hooks.test.d.ts.map +1 -0
  52. package/dist/lib/git-hooks.test.js +178 -0
  53. package/dist/lib/git-hooks.test.js.map +1 -0
  54. package/dist/lib/git.d.ts +10 -0
  55. package/dist/lib/git.d.ts.map +1 -1
  56. package/dist/lib/git.js +32 -0
  57. package/dist/lib/git.js.map +1 -1
  58. package/dist/lib/hook-templates.d.ts +12 -0
  59. package/dist/lib/hook-templates.d.ts.map +1 -0
  60. package/dist/lib/hook-templates.js +52 -0
  61. package/dist/lib/hook-templates.js.map +1 -0
  62. package/dist/lib/hook-templates.test.d.ts +11 -0
  63. package/dist/lib/hook-templates.test.d.ts.map +1 -0
  64. package/dist/lib/hook-templates.test.js +76 -0
  65. package/dist/lib/hook-templates.test.js.map +1 -0
  66. package/dist/lib/hooks-types.d.ts +30 -0
  67. package/dist/lib/hooks-types.d.ts.map +1 -0
  68. package/dist/lib/hooks-types.js +9 -0
  69. package/dist/lib/hooks-types.js.map +1 -0
  70. package/package.json +2 -2
@@ -0,0 +1,44 @@
1
+ /**
2
+ * `ghagga hooks uninstall` subcommand.
3
+ *
4
+ * Removes GHAGGA-managed hooks from the current git repository.
5
+ * Only removes hooks that contain the GHAGGA marker comment.
6
+ * Restores backed-up hooks if they exist.
7
+ *
8
+ * @see Phase 3, Task 3.3
9
+ */
10
+ import { isGitRepo, getHooksDir, uninstallHook } from '../../lib/git-hooks.js';
11
+ import * as tui from '../../ui/tui.js';
12
+ const HOOK_TYPES = ['pre-commit', 'commit-msg'];
13
+ export function registerUninstallCommand(parent) {
14
+ parent
15
+ .command('uninstall')
16
+ .description('Remove GHAGGA-managed git hooks')
17
+ .action(() => {
18
+ if (!isGitRepo()) {
19
+ tui.log.error('Not a git repository. Run this command from inside a git repo.');
20
+ process.exit(1);
21
+ }
22
+ const hooksDir = getHooksDir();
23
+ let removed = 0;
24
+ for (const hookType of HOOK_TYPES) {
25
+ const result = uninstallHook(hooksDir, hookType);
26
+ if (result.success) {
27
+ tui.log.success(result.message);
28
+ if (result.message.includes('Removed')) {
29
+ removed++;
30
+ }
31
+ }
32
+ else {
33
+ tui.log.warn(result.message);
34
+ }
35
+ }
36
+ if (removed > 0) {
37
+ tui.log.info(`\nRemoved ${removed} GHAGGA hook(s) from ${hooksDir}`);
38
+ }
39
+ else {
40
+ tui.log.info('\nNo GHAGGA hooks were found to remove.');
41
+ }
42
+ });
43
+ }
44
+ //# sourceMappingURL=uninstall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uninstall.js","sourceRoot":"","sources":["../../../src/commands/hooks/uninstall.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE/E,OAAO,KAAK,GAAG,MAAM,iBAAiB,CAAC;AAEvC,MAAM,UAAU,GAAe,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;AAE5D,MAAM,UAAU,wBAAwB,CAAC,MAAe;IACtD,MAAM;SACH,OAAO,CAAC,WAAW,CAAC;SACpB,WAAW,CAAC,iCAAiC,CAAC;SAC9C,MAAM,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;YACjB,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,gEAAgE,CAAC,CAAC;YAChF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;QAC/B,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;YAClC,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAEjD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAChC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;oBACvC,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QAED,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,OAAO,wBAAwB,QAAQ,EAAE,CAAC,CAAC;QACvE,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Tests for `ghagga hooks uninstall` subcommand.
3
+ *
4
+ * Mocks git-hooks utilities and the TUI layer.
5
+ * Tests uninstall of both hooks, non-git-repo error, and result messages.
6
+ *
7
+ * @see Phase 4, Test 5
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=uninstall.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uninstall.test.d.ts","sourceRoot":"","sources":["../../../src/commands/hooks/uninstall.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Tests for `ghagga hooks uninstall` subcommand.
3
+ *
4
+ * Mocks git-hooks utilities and the TUI layer.
5
+ * Tests uninstall of both hooks, non-git-repo error, and result messages.
6
+ *
7
+ * @see Phase 4, Test 5
8
+ */
9
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
10
+ import { Command } from 'commander';
11
+ // ─── Mocks ──────────────────────────────────────────────────────
12
+ const { mockIsGitRepo, mockGetHooksDir, mockUninstallHook } = vi.hoisted(() => ({
13
+ mockIsGitRepo: vi.fn(),
14
+ mockGetHooksDir: vi.fn(),
15
+ mockUninstallHook: vi.fn(),
16
+ }));
17
+ vi.mock('../../lib/git-hooks.js', () => ({
18
+ isGitRepo: (...args) => mockIsGitRepo(...args),
19
+ getHooksDir: (...args) => mockGetHooksDir(...args),
20
+ uninstallHook: (...args) => mockUninstallHook(...args),
21
+ }));
22
+ vi.mock('../../ui/tui.js', () => ({
23
+ log: {
24
+ success: vi.fn(),
25
+ error: vi.fn(),
26
+ info: vi.fn(),
27
+ warn: vi.fn(),
28
+ },
29
+ }));
30
+ import { registerUninstallCommand } from './uninstall.js';
31
+ import * as tui from '../../ui/tui.js';
32
+ // ─── Helpers ────────────────────────────────────────────────────
33
+ class ProcessExitError extends Error {
34
+ code;
35
+ constructor(code) {
36
+ super(`process.exit(${code})`);
37
+ this.code = code;
38
+ }
39
+ }
40
+ async function runUninstallCommand(args = []) {
41
+ const parent = new Command('hooks');
42
+ registerUninstallCommand(parent);
43
+ try {
44
+ await parent.parseAsync(['uninstall', ...args], { from: 'user' });
45
+ }
46
+ catch (err) {
47
+ if (!(err instanceof ProcessExitError))
48
+ throw err;
49
+ }
50
+ }
51
+ // ─── Setup ──────────────────────────────────────────────────────
52
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
53
+ let exitSpy;
54
+ beforeEach(() => {
55
+ vi.clearAllMocks();
56
+ exitSpy = vi
57
+ .spyOn(process, 'exit')
58
+ .mockImplementation(((code) => {
59
+ throw new ProcessExitError(code);
60
+ }));
61
+ mockIsGitRepo.mockReturnValue(true);
62
+ mockGetHooksDir.mockReturnValue('/repo/.git/hooks');
63
+ });
64
+ afterEach(() => {
65
+ exitSpy.mockRestore();
66
+ });
67
+ // ─── Tests ──────────────────────────────────────────────────────
68
+ describe('ghagga hooks uninstall', () => {
69
+ it('calls uninstallHook for both pre-commit and commit-msg', async () => {
70
+ mockUninstallHook
71
+ .mockReturnValueOnce({ type: 'pre-commit', success: true, message: 'Removed pre-commit hook' })
72
+ .mockReturnValueOnce({ type: 'commit-msg', success: true, message: 'Removed commit-msg hook' });
73
+ await runUninstallCommand();
74
+ expect(mockUninstallHook).toHaveBeenCalledTimes(2);
75
+ expect(mockUninstallHook).toHaveBeenCalledWith('/repo/.git/hooks', 'pre-commit');
76
+ expect(mockUninstallHook).toHaveBeenCalledWith('/repo/.git/hooks', 'commit-msg');
77
+ });
78
+ it('exits with error when not in a git repo', async () => {
79
+ mockIsGitRepo.mockReturnValue(false);
80
+ await runUninstallCommand();
81
+ expect(exitSpy).toHaveBeenCalledWith(1);
82
+ expect(tui.log.error).toHaveBeenCalledWith(expect.stringContaining('Not a git repository'));
83
+ expect(mockUninstallHook).not.toHaveBeenCalled();
84
+ });
85
+ it('shows success messages for removed hooks', async () => {
86
+ mockUninstallHook
87
+ .mockReturnValueOnce({ type: 'pre-commit', success: true, message: 'Removed pre-commit hook' })
88
+ .mockReturnValueOnce({ type: 'commit-msg', success: true, message: 'Removed commit-msg hook' });
89
+ await runUninstallCommand();
90
+ expect(tui.log.success).toHaveBeenCalledWith('Removed pre-commit hook');
91
+ expect(tui.log.success).toHaveBeenCalledWith('Removed commit-msg hook');
92
+ expect(tui.log.info).toHaveBeenCalledWith(expect.stringContaining('Removed 2 GHAGGA hook(s)'));
93
+ });
94
+ it('shows warn for skipped external hooks', async () => {
95
+ mockUninstallHook.mockReturnValue({
96
+ type: 'pre-commit',
97
+ success: false,
98
+ message: 'Hook pre-commit exists but is not managed by GHAGGA. Skipping.',
99
+ });
100
+ await runUninstallCommand();
101
+ expect(tui.log.warn).toHaveBeenCalledWith(expect.stringContaining('not managed by GHAGGA'));
102
+ });
103
+ it('shows info when no GHAGGA hooks were found', async () => {
104
+ mockUninstallHook.mockReturnValue({
105
+ type: 'pre-commit',
106
+ success: true,
107
+ message: 'Hook pre-commit not installed, nothing to remove',
108
+ });
109
+ await runUninstallCommand();
110
+ expect(tui.log.info).toHaveBeenCalledWith(expect.stringContaining('No GHAGGA hooks were found to remove'));
111
+ });
112
+ it('shows correct count when only one hook is actually removed', async () => {
113
+ mockUninstallHook
114
+ .mockReturnValueOnce({ type: 'pre-commit', success: true, message: 'Removed pre-commit hook' })
115
+ .mockReturnValueOnce({ type: 'commit-msg', success: true, message: 'Hook commit-msg not installed, nothing to remove' });
116
+ await runUninstallCommand();
117
+ expect(tui.log.info).toHaveBeenCalledWith(expect.stringContaining('Removed 1 GHAGGA hook(s)'));
118
+ });
119
+ });
120
+ //# sourceMappingURL=uninstall.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uninstall.test.js","sourceRoot":"","sources":["../../../src/commands/hooks/uninstall.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Commit message review — lightweight validation + optional LLM review.
3
+ *
4
+ * Used by `ghagga review --commit-msg <file>` for the commit-msg hook.
5
+ * Validates basic commit message format (heuristics) and optionally
6
+ * calls a single LLM prompt for quality assessment.
7
+ *
8
+ * Returns a ReviewResult-compatible structure for consistent exit-code handling.
9
+ */
10
+ import type { LLMProvider, ReviewResult } from 'ghagga-core';
11
+ export interface CommitMsgReviewOptions {
12
+ /** Raw commit message string (file contents) */
13
+ message: string;
14
+ /** LLM provider */
15
+ provider: LLMProvider;
16
+ /** LLM model identifier */
17
+ model: string;
18
+ /** API key for the LLM provider */
19
+ apiKey: string;
20
+ /** When true, skip LLM and use heuristics only */
21
+ quick?: boolean;
22
+ }
23
+ /**
24
+ * Validate a commit message using heuristics and optional LLM review.
25
+ * Returns a ReviewResult for consistent exit-code and output handling.
26
+ */
27
+ export declare function reviewCommitMessage(opts: CommitMsgReviewOptions): Promise<ReviewResult>;
28
+ //# sourceMappingURL=review-commit-msg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-commit-msg.d.ts","sourceRoot":"","sources":["../../src/commands/review-commit-msg.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EAIb,MAAM,aAAa,CAAC;AAIrB,MAAM,WAAW,sBAAsB;IACrC,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,mBAAmB;IACnB,QAAQ,EAAE,WAAW,CAAC;IACtB,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAoFD;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,YAAY,CAAC,CAyDvB"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Commit message review — lightweight validation + optional LLM review.
3
+ *
4
+ * Used by `ghagga review --commit-msg <file>` for the commit-msg hook.
5
+ * Validates basic commit message format (heuristics) and optionally
6
+ * calls a single LLM prompt for quality assessment.
7
+ *
8
+ * Returns a ReviewResult-compatible structure for consistent exit-code handling.
9
+ */
10
+ /**
11
+ * Strip comment lines (starting with #) from a commit message.
12
+ * Git includes these as hints in the COMMIT_EDITMSG file.
13
+ */
14
+ function stripComments(message) {
15
+ return message
16
+ .split('\n')
17
+ .filter((line) => !line.startsWith('#'))
18
+ .join('\n')
19
+ .trim();
20
+ }
21
+ /**
22
+ * Run heuristic validations on a commit message.
23
+ * Returns an array of findings (empty = message is fine).
24
+ */
25
+ function validateHeuristics(message) {
26
+ const findings = [];
27
+ const cleaned = stripComments(message);
28
+ // Empty message
29
+ if (cleaned.length === 0) {
30
+ findings.push({
31
+ severity: 'high',
32
+ message: 'Commit message is empty',
33
+ suggestion: 'Write a descriptive commit message explaining the change',
34
+ });
35
+ return findings; // No point checking further
36
+ }
37
+ // Too short (likely meaningless like "fix" or "wip")
38
+ if (cleaned.length <= 3) {
39
+ findings.push({
40
+ severity: 'high',
41
+ message: `Commit message is too short (${cleaned.length} chars)`,
42
+ suggestion: 'Write a descriptive message explaining what changed and why',
43
+ });
44
+ }
45
+ const lines = cleaned.split('\n');
46
+ const subject = lines[0] ?? '';
47
+ // Subject line > 72 chars
48
+ if (subject.length > 72) {
49
+ findings.push({
50
+ severity: 'medium',
51
+ message: `Subject line is ${subject.length} characters (recommended max: 72)`,
52
+ suggestion: 'Keep the subject line concise; move details to the body',
53
+ });
54
+ }
55
+ // Subject ends with period
56
+ if (subject.endsWith('.')) {
57
+ findings.push({
58
+ severity: 'low',
59
+ message: 'Subject line ends with a period',
60
+ suggestion: 'Remove the trailing period from the subject line',
61
+ });
62
+ }
63
+ // Body not separated by blank line
64
+ if (lines.length > 1 && lines[1] !== '') {
65
+ findings.push({
66
+ severity: 'medium',
67
+ message: 'Body is not separated from subject by a blank line',
68
+ suggestion: 'Add a blank line between the subject and body',
69
+ });
70
+ }
71
+ return findings;
72
+ }
73
+ // ─── Main Function ──────────────────────────────────────────────
74
+ /**
75
+ * Validate a commit message using heuristics and optional LLM review.
76
+ * Returns a ReviewResult for consistent exit-code and output handling.
77
+ */
78
+ export async function reviewCommitMessage(opts) {
79
+ const startTime = Date.now();
80
+ const findings = [];
81
+ // ── Step 1: Heuristic validation ──────────────────────────
82
+ const heuristicFindings = validateHeuristics(opts.message);
83
+ for (const hf of heuristicFindings) {
84
+ findings.push({
85
+ severity: hf.severity,
86
+ category: hf.severity === 'low' ? 'style' : 'convention',
87
+ file: 'COMMIT_EDITMSG',
88
+ message: hf.message,
89
+ suggestion: hf.suggestion,
90
+ source: 'ai', // Use 'ai' as closest match in FindingSource union
91
+ });
92
+ }
93
+ // ── Step 2: LLM review (skip in quick mode) ───────────────
94
+ // Note: LLM commit message review is a future enhancement.
95
+ // For now, heuristic validation covers the essential checks.
96
+ // When --quick is NOT set and we have a non-empty message,
97
+ // a future version will call a single LLM prompt here.
98
+ // ── Step 3: Determine status ──────────────────────────────
99
+ const hasBlockingIssues = findings.some((f) => f.severity === 'critical' || f.severity === 'high');
100
+ const status = hasBlockingIssues ? 'FAILED' : 'PASSED';
101
+ const executionTimeMs = Date.now() - startTime;
102
+ const summary = findings.length === 0
103
+ ? 'Commit message looks good.'
104
+ : `Found ${findings.length} issue(s) in commit message.`;
105
+ return {
106
+ status,
107
+ summary,
108
+ findings,
109
+ staticAnalysis: {
110
+ semgrep: { status: 'skipped', findings: [], executionTimeMs: 0 },
111
+ trivy: { status: 'skipped', findings: [], executionTimeMs: 0 },
112
+ cpd: { status: 'skipped', findings: [], executionTimeMs: 0 },
113
+ },
114
+ memoryContext: null,
115
+ metadata: {
116
+ mode: 'simple',
117
+ provider: opts.quick ? 'none' : opts.provider,
118
+ model: opts.quick ? 'static-only' : opts.model,
119
+ tokensUsed: 0,
120
+ executionTimeMs,
121
+ toolsRun: [],
122
+ toolsSkipped: ['semgrep', 'trivy', 'cpd'],
123
+ },
124
+ };
125
+ }
126
+ //# sourceMappingURL=review-commit-msg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-commit-msg.js","sourceRoot":"","sources":["../../src/commands/review-commit-msg.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Tests for commit message review (heuristic validation).
3
+ *
4
+ * Validates that reviewCommitMessage() correctly identifies
5
+ * empty, too-short, long subject, trailing period, missing blank line,
6
+ * git comments, and multiple issues. Also verifies quick mode skips AI.
7
+ *
8
+ * @see Phase 4, Test 3
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=review-commit-msg.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-commit-msg.test.d.ts","sourceRoot":"","sources":["../../src/commands/review-commit-msg.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Tests for commit message review (heuristic validation).
3
+ *
4
+ * Validates that reviewCommitMessage() correctly identifies
5
+ * empty, too-short, long subject, trailing period, missing blank line,
6
+ * git comments, and multiple issues. Also verifies quick mode skips AI.
7
+ *
8
+ * @see Phase 4, Test 3
9
+ */
10
+ import { describe, it, expect } from 'vitest';
11
+ import { reviewCommitMessage } from './review-commit-msg.js';
12
+ // ─── Helpers ────────────────────────────────────────────────────
13
+ /** Default options for tests (quick mode — heuristics only) */
14
+ function makeOpts(message, overrides = {}) {
15
+ return {
16
+ message,
17
+ provider: 'anthropic',
18
+ model: 'claude-sonnet-4-20250514',
19
+ apiKey: 'test-key',
20
+ quick: true,
21
+ ...overrides,
22
+ };
23
+ }
24
+ // ─── Tests ──────────────────────────────────────────────────────
25
+ describe('reviewCommitMessage — heuristic validation', () => {
26
+ it('flags empty message with high severity', async () => {
27
+ const result = await reviewCommitMessage(makeOpts(''));
28
+ expect(result.status).toBe('FAILED');
29
+ expect(result.findings).toHaveLength(1);
30
+ expect(result.findings[0].severity).toBe('high');
31
+ expect(result.findings[0].message).toContain('empty');
32
+ });
33
+ it('flags too-short message (≤ 3 chars) with high severity', async () => {
34
+ const result = await reviewCommitMessage(makeOpts('fix'));
35
+ expect(result.status).toBe('FAILED');
36
+ expect(result.findings.length).toBeGreaterThanOrEqual(1);
37
+ const shortFinding = result.findings.find((f) => f.message.includes('too short'));
38
+ expect(shortFinding).toBeDefined();
39
+ expect(shortFinding.severity).toBe('high');
40
+ });
41
+ it('flags subject line > 72 chars with medium severity', async () => {
42
+ const longSubject = 'a'.repeat(80);
43
+ const result = await reviewCommitMessage(makeOpts(longSubject));
44
+ const finding = result.findings.find((f) => f.message.includes('72'));
45
+ expect(finding).toBeDefined();
46
+ expect(finding.severity).toBe('medium');
47
+ });
48
+ it('flags subject ending with period with low severity', async () => {
49
+ const result = await reviewCommitMessage(makeOpts('Add new feature for users.'));
50
+ const finding = result.findings.find((f) => f.message.includes('period'));
51
+ expect(finding).toBeDefined();
52
+ expect(finding.severity).toBe('low');
53
+ });
54
+ it('flags body not separated by blank line with medium severity', async () => {
55
+ const msg = 'Add feature\nThis is the body without blank line';
56
+ const result = await reviewCommitMessage(makeOpts(msg));
57
+ const finding = result.findings.find((f) => f.message.includes('blank line'));
58
+ expect(finding).toBeDefined();
59
+ expect(finding.severity).toBe('medium');
60
+ });
61
+ it('returns no findings for a valid conventional commit', async () => {
62
+ const msg = 'feat(auth): add OAuth token refresh support';
63
+ const result = await reviewCommitMessage(makeOpts(msg));
64
+ expect(result.status).toBe('PASSED');
65
+ expect(result.findings).toHaveLength(0);
66
+ expect(result.summary).toContain('looks good');
67
+ });
68
+ it('strips git comment lines (# lines) before validation', async () => {
69
+ const msg = [
70
+ 'feat: add new feature',
71
+ '',
72
+ '# Please enter the commit message',
73
+ '# Lines starting with # will be ignored.',
74
+ ].join('\n');
75
+ const result = await reviewCommitMessage(makeOpts(msg));
76
+ expect(result.status).toBe('PASSED');
77
+ expect(result.findings).toHaveLength(0);
78
+ });
79
+ it('detects multiple issues simultaneously', async () => {
80
+ // Long subject + ends with period + body without blank line
81
+ const longSubject = 'a'.repeat(80) + '.';
82
+ const msg = `${longSubject}\nBody without blank separator`;
83
+ const result = await reviewCommitMessage(makeOpts(msg));
84
+ // Should have at least 3 findings: long subject, period, no blank line
85
+ expect(result.findings.length).toBeGreaterThanOrEqual(3);
86
+ const severities = result.findings.map((f) => f.severity);
87
+ expect(severities).toContain('medium'); // long subject or blank line
88
+ expect(severities).toContain('low'); // period
89
+ });
90
+ it('uses "static-only" model in quick mode metadata', async () => {
91
+ const result = await reviewCommitMessage(makeOpts('feat: valid commit', { quick: true }));
92
+ expect(result.metadata.model).toBe('static-only');
93
+ expect(result.metadata.provider).toBe('none');
94
+ });
95
+ it('records actual provider and model when quick is false', async () => {
96
+ const result = await reviewCommitMessage(makeOpts('feat: valid commit', { quick: false }));
97
+ expect(result.metadata.provider).toBe('anthropic');
98
+ expect(result.metadata.model).toBe('claude-sonnet-4-20250514');
99
+ });
100
+ it('sets file to COMMIT_EDITMSG in all findings', async () => {
101
+ const result = await reviewCommitMessage(makeOpts(''));
102
+ for (const finding of result.findings) {
103
+ expect(finding.file).toBe('COMMIT_EDITMSG');
104
+ }
105
+ });
106
+ it('skips all static analysis tools', async () => {
107
+ const result = await reviewCommitMessage(makeOpts('feat: valid'));
108
+ expect(result.staticAnalysis.semgrep.status).toBe('skipped');
109
+ expect(result.staticAnalysis.trivy.status).toBe('skipped');
110
+ expect(result.staticAnalysis.cpd.status).toBe('skipped');
111
+ });
112
+ it('returns PASSED status when only low-severity findings exist', async () => {
113
+ const result = await reviewCommitMessage(makeOpts('Add new feature for users.'));
114
+ // Only low severity (period) — should still pass
115
+ const hasCriticalOrHigh = result.findings.some((f) => f.severity === 'critical' || f.severity === 'high');
116
+ expect(hasCriticalOrHigh).toBe(false);
117
+ expect(result.status).toBe('PASSED');
118
+ });
119
+ it('includes valid body separated by blank line without findings', async () => {
120
+ const msg = 'feat(core): add caching layer\n\nThis adds Redis-based caching.';
121
+ const result = await reviewCommitMessage(makeOpts(msg));
122
+ expect(result.status).toBe('PASSED');
123
+ expect(result.findings).toHaveLength(0);
124
+ });
125
+ });
126
+ //# sourceMappingURL=review-commit-msg.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-commit-msg.test.js","sourceRoot":"","sources":["../../src/commands/review-commit-msg.test.ts"],"names":[],"mappings":"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"}
@@ -16,8 +16,14 @@ export interface ReviewOptions {
16
16
  trivy: boolean;
17
17
  cpd: boolean;
18
18
  memory: boolean;
19
+ /** Memory backend: 'sqlite' (default) or 'engram' */
20
+ memoryBackend?: 'sqlite' | 'engram';
19
21
  config?: string;
20
22
  verbose: boolean;
23
+ staged?: boolean;
24
+ commitMsg?: string;
25
+ exitOnIssues?: boolean;
26
+ quick?: boolean;
21
27
  }
22
28
  export declare function reviewCommand(targetPath: string, options: ReviewOptions): Promise<void>;
23
29
  //# sourceMappingURL=review.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/commands/review.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EAMZ,MAAM,aAAa,CAAC;AASrB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,WAAW,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAgBD,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC,CAuFf"}
1
+ {"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/commands/review.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAWH,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EAOZ,MAAM,aAAa,CAAC;AAUrB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,WAAW,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,qDAAqD;IACrD,aAAa,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IAEjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAgBD,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC,CAiLf"}