ghagga 2.0.1 → 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 (193) hide show
  1. package/README.md +90 -19
  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/login.d.ts.map +1 -1
  31. package/dist/commands/login.js +17 -14
  32. package/dist/commands/login.js.map +1 -1
  33. package/dist/commands/login.test.d.ts +9 -0
  34. package/dist/commands/login.test.d.ts.map +1 -0
  35. package/dist/commands/login.test.js +138 -0
  36. package/dist/commands/login.test.js.map +1 -0
  37. package/dist/commands/logout.d.ts.map +1 -1
  38. package/dist/commands/logout.js +4 -3
  39. package/dist/commands/logout.js.map +1 -1
  40. package/dist/commands/logout.test.d.ts +8 -0
  41. package/dist/commands/logout.test.d.ts.map +1 -0
  42. package/dist/commands/logout.test.js +61 -0
  43. package/dist/commands/logout.test.js.map +1 -0
  44. package/dist/commands/memory/clear.d.ts +11 -0
  45. package/dist/commands/memory/clear.d.ts.map +1 -0
  46. package/dist/commands/memory/clear.js +45 -0
  47. package/dist/commands/memory/clear.js.map +1 -0
  48. package/dist/commands/memory/clear.test.d.ts +11 -0
  49. package/dist/commands/memory/clear.test.d.ts.map +1 -0
  50. package/dist/commands/memory/clear.test.js +178 -0
  51. package/dist/commands/memory/clear.test.js.map +1 -0
  52. package/dist/commands/memory/delete.d.ts +11 -0
  53. package/dist/commands/memory/delete.d.ts.map +1 -0
  54. package/dist/commands/memory/delete.js +38 -0
  55. package/dist/commands/memory/delete.js.map +1 -0
  56. package/dist/commands/memory/delete.test.d.ts +11 -0
  57. package/dist/commands/memory/delete.test.d.ts.map +1 -0
  58. package/dist/commands/memory/delete.test.js +176 -0
  59. package/dist/commands/memory/delete.test.js.map +1 -0
  60. package/dist/commands/memory/index.d.ts +10 -0
  61. package/dist/commands/memory/index.d.ts.map +1 -0
  62. package/dist/commands/memory/index.js +23 -0
  63. package/dist/commands/memory/index.js.map +1 -0
  64. package/dist/commands/memory/list.d.ts +11 -0
  65. package/dist/commands/memory/list.d.ts.map +1 -0
  66. package/dist/commands/memory/list.js +47 -0
  67. package/dist/commands/memory/list.js.map +1 -0
  68. package/dist/commands/memory/list.test.d.ts +10 -0
  69. package/dist/commands/memory/list.test.d.ts.map +1 -0
  70. package/dist/commands/memory/list.test.js +135 -0
  71. package/dist/commands/memory/list.test.js.map +1 -0
  72. package/dist/commands/memory/search.d.ts +12 -0
  73. package/dist/commands/memory/search.d.ts.map +1 -0
  74. package/dist/commands/memory/search.js +44 -0
  75. package/dist/commands/memory/search.js.map +1 -0
  76. package/dist/commands/memory/search.test.d.ts +11 -0
  77. package/dist/commands/memory/search.test.d.ts.map +1 -0
  78. package/dist/commands/memory/search.test.js +122 -0
  79. package/dist/commands/memory/search.test.js.map +1 -0
  80. package/dist/commands/memory/show.d.ts +10 -0
  81. package/dist/commands/memory/show.d.ts.map +1 -0
  82. package/dist/commands/memory/show.js +51 -0
  83. package/dist/commands/memory/show.js.map +1 -0
  84. package/dist/commands/memory/show.test.d.ts +11 -0
  85. package/dist/commands/memory/show.test.d.ts.map +1 -0
  86. package/dist/commands/memory/show.test.js +156 -0
  87. package/dist/commands/memory/show.test.js.map +1 -0
  88. package/dist/commands/memory/stats.d.ts +11 -0
  89. package/dist/commands/memory/stats.d.ts.map +1 -0
  90. package/dist/commands/memory/stats.js +63 -0
  91. package/dist/commands/memory/stats.js.map +1 -0
  92. package/dist/commands/memory/stats.test.d.ts +10 -0
  93. package/dist/commands/memory/stats.test.d.ts.map +1 -0
  94. package/dist/commands/memory/stats.test.js +122 -0
  95. package/dist/commands/memory/stats.test.js.map +1 -0
  96. package/dist/commands/memory/utils.d.ts +44 -0
  97. package/dist/commands/memory/utils.d.ts.map +1 -0
  98. package/dist/commands/memory/utils.js +90 -0
  99. package/dist/commands/memory/utils.js.map +1 -0
  100. package/dist/commands/memory/utils.test.d.ts +10 -0
  101. package/dist/commands/memory/utils.test.d.ts.map +1 -0
  102. package/dist/commands/memory/utils.test.js +93 -0
  103. package/dist/commands/memory/utils.test.js.map +1 -0
  104. package/dist/commands/review-commit-msg.d.ts +28 -0
  105. package/dist/commands/review-commit-msg.d.ts.map +1 -0
  106. package/dist/commands/review-commit-msg.js +126 -0
  107. package/dist/commands/review-commit-msg.js.map +1 -0
  108. package/dist/commands/review-commit-msg.test.d.ts +11 -0
  109. package/dist/commands/review-commit-msg.test.d.ts.map +1 -0
  110. package/dist/commands/review-commit-msg.test.js +126 -0
  111. package/dist/commands/review-commit-msg.test.js.map +1 -0
  112. package/dist/commands/review.d.ts +7 -0
  113. package/dist/commands/review.d.ts.map +1 -1
  114. package/dist/commands/review.js +138 -103
  115. package/dist/commands/review.js.map +1 -1
  116. package/dist/commands/review.test.js +267 -1
  117. package/dist/commands/review.test.js.map +1 -1
  118. package/dist/commands/status.d.ts.map +1 -1
  119. package/dist/commands/status.js +12 -11
  120. package/dist/commands/status.js.map +1 -1
  121. package/dist/commands/status.test.d.ts +8 -0
  122. package/dist/commands/status.test.d.ts.map +1 -0
  123. package/dist/commands/status.test.js +106 -0
  124. package/dist/commands/status.test.js.map +1 -0
  125. package/dist/index.d.ts +5 -4
  126. package/dist/index.d.ts.map +1 -1
  127. package/dist/index.js +48 -16
  128. package/dist/index.js.map +1 -1
  129. package/dist/lib/config.d.ts +1 -0
  130. package/dist/lib/config.d.ts.map +1 -1
  131. package/dist/lib/config.js +1 -1
  132. package/dist/lib/config.js.map +1 -1
  133. package/dist/lib/config.test.d.ts +9 -0
  134. package/dist/lib/config.test.d.ts.map +1 -0
  135. package/dist/lib/config.test.js +181 -0
  136. package/dist/lib/config.test.js.map +1 -0
  137. package/dist/lib/git-hooks.d.ts +19 -0
  138. package/dist/lib/git-hooks.d.ts.map +1 -0
  139. package/dist/lib/git-hooks.js +129 -0
  140. package/dist/lib/git-hooks.js.map +1 -0
  141. package/dist/lib/git-hooks.test.d.ts +11 -0
  142. package/dist/lib/git-hooks.test.d.ts.map +1 -0
  143. package/dist/lib/git-hooks.test.js +178 -0
  144. package/dist/lib/git-hooks.test.js.map +1 -0
  145. package/dist/lib/git.d.ts +33 -0
  146. package/dist/lib/git.d.ts.map +1 -0
  147. package/dist/lib/git.js +85 -0
  148. package/dist/lib/git.js.map +1 -0
  149. package/dist/lib/git.test.d.ts +2 -0
  150. package/dist/lib/git.test.d.ts.map +1 -0
  151. package/dist/lib/git.test.js +65 -0
  152. package/dist/lib/git.test.js.map +1 -0
  153. package/dist/lib/hook-templates.d.ts +12 -0
  154. package/dist/lib/hook-templates.d.ts.map +1 -0
  155. package/dist/lib/hook-templates.js +52 -0
  156. package/dist/lib/hook-templates.js.map +1 -0
  157. package/dist/lib/hook-templates.test.d.ts +11 -0
  158. package/dist/lib/hook-templates.test.d.ts.map +1 -0
  159. package/dist/lib/hook-templates.test.js +76 -0
  160. package/dist/lib/hook-templates.test.js.map +1 -0
  161. package/dist/lib/hooks-types.d.ts +30 -0
  162. package/dist/lib/hooks-types.d.ts.map +1 -0
  163. package/dist/lib/hooks-types.js +9 -0
  164. package/dist/lib/hooks-types.js.map +1 -0
  165. package/dist/lib/oauth.test.d.ts +8 -0
  166. package/dist/lib/oauth.test.d.ts.map +1 -0
  167. package/dist/lib/oauth.test.js +212 -0
  168. package/dist/lib/oauth.test.js.map +1 -0
  169. package/dist/ui/__tests__/format.test.d.ts +7 -0
  170. package/dist/ui/__tests__/format.test.d.ts.map +1 -0
  171. package/dist/ui/__tests__/format.test.js +220 -0
  172. package/dist/ui/__tests__/format.test.js.map +1 -0
  173. package/dist/ui/__tests__/theme.test.d.ts +7 -0
  174. package/dist/ui/__tests__/theme.test.d.ts.map +1 -0
  175. package/dist/ui/__tests__/theme.test.js +79 -0
  176. package/dist/ui/__tests__/theme.test.js.map +1 -0
  177. package/dist/ui/__tests__/tui.test.d.ts +9 -0
  178. package/dist/ui/__tests__/tui.test.d.ts.map +1 -0
  179. package/dist/ui/__tests__/tui.test.js +222 -0
  180. package/dist/ui/__tests__/tui.test.js.map +1 -0
  181. package/dist/ui/format.d.ts +38 -0
  182. package/dist/ui/format.d.ts.map +1 -0
  183. package/dist/ui/format.js +136 -0
  184. package/dist/ui/format.js.map +1 -0
  185. package/dist/ui/theme.d.ts +26 -0
  186. package/dist/ui/theme.d.ts.map +1 -0
  187. package/dist/ui/theme.js +63 -0
  188. package/dist/ui/theme.js.map +1 -0
  189. package/dist/ui/tui.d.ts +44 -0
  190. package/dist/ui/tui.d.ts.map +1 -0
  191. package/dist/ui/tui.js +121 -0
  192. package/dist/ui/tui.js.map +1 -0
  193. package/package.json +4 -2
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Tests for git hook utilities (install, uninstall, status).
3
+ *
4
+ * Mocks node:fs, node:child_process, and node:path to test
5
+ * isGitRepo, getHooksDir, getHookStatus, installHook, and uninstallHook
6
+ * without touching the real filesystem or git.
7
+ *
8
+ * @see Phase 4, Test 2
9
+ */
10
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
11
+ import { HOOK_MARKER } from './hooks-types.js';
12
+ // ─── Mocks ──────────────────────────────────────────────────────
13
+ const { mockExecSync, mockExistsSync, mockReadFileSync, mockWriteFileSync, mockUnlinkSync, mockRenameSync, mockChmodSync, } = vi.hoisted(() => ({
14
+ mockExecSync: vi.fn(),
15
+ mockExistsSync: vi.fn(),
16
+ mockReadFileSync: vi.fn(),
17
+ mockWriteFileSync: vi.fn(),
18
+ mockUnlinkSync: vi.fn(),
19
+ mockRenameSync: vi.fn(),
20
+ mockChmodSync: vi.fn(),
21
+ }));
22
+ vi.mock('node:child_process', () => ({
23
+ execSync: (...args) => mockExecSync(...args),
24
+ }));
25
+ vi.mock('node:fs', () => ({
26
+ existsSync: (...args) => mockExistsSync(...args),
27
+ readFileSync: (...args) => mockReadFileSync(...args),
28
+ writeFileSync: (...args) => mockWriteFileSync(...args),
29
+ unlinkSync: (...args) => mockUnlinkSync(...args),
30
+ renameSync: (...args) => mockRenameSync(...args),
31
+ chmodSync: (...args) => mockChmodSync(...args),
32
+ }));
33
+ import { isGitRepo, getHooksDir, getHookStatus, installHook, uninstallHook, } from './git-hooks.js';
34
+ // ─── Setup ──────────────────────────────────────────────────────
35
+ beforeEach(() => {
36
+ vi.clearAllMocks();
37
+ });
38
+ // ─── isGitRepo ──────────────────────────────────────────────────
39
+ describe('isGitRepo', () => {
40
+ it('returns true when inside a git repository', () => {
41
+ mockExecSync.mockReturnValue('.git');
42
+ expect(isGitRepo()).toBe(true);
43
+ expect(mockExecSync).toHaveBeenCalledWith('git rev-parse --git-dir', { stdio: 'pipe' });
44
+ });
45
+ it('returns false when outside a git repository', () => {
46
+ mockExecSync.mockImplementation(() => {
47
+ throw new Error('not a git repository');
48
+ });
49
+ expect(isGitRepo()).toBe(false);
50
+ });
51
+ });
52
+ // ─── getHooksDir ────────────────────────────────────────────────
53
+ describe('getHooksDir', () => {
54
+ it('returns default .git/hooks when no core.hooksPath is set', () => {
55
+ mockExecSync
56
+ .mockImplementationOnce(() => {
57
+ // core.hooksPath fails (not set)
58
+ throw new Error('key does not exist');
59
+ })
60
+ .mockReturnValueOnce('.git\n'); // git rev-parse --git-dir
61
+ const result = getHooksDir();
62
+ expect(result).toMatch(/\.git[/\\]hooks$/);
63
+ });
64
+ it('respects core.hooksPath config when set', () => {
65
+ mockExecSync.mockReturnValueOnce('/custom/hooks-dir\n'); // core.hooksPath
66
+ const result = getHooksDir();
67
+ expect(result).toBe('/custom/hooks-dir');
68
+ });
69
+ });
70
+ // ─── getHookStatus ──────────────────────────────────────────────
71
+ describe('getHookStatus', () => {
72
+ it('returns not installed when hook file does not exist', () => {
73
+ mockExistsSync.mockReturnValue(false);
74
+ const status = getHookStatus('/repo/.git/hooks', 'pre-commit');
75
+ expect(status.installed).toBe(false);
76
+ expect(status.managedByGhagga).toBe(false);
77
+ expect(status.type).toBe('pre-commit');
78
+ });
79
+ it('returns managed when GHAGGA marker is found in hook file', () => {
80
+ mockExistsSync.mockReturnValue(true);
81
+ mockReadFileSync.mockReturnValue(`#!/bin/sh\n${HOOK_MARKER}\nexec ghagga review`);
82
+ const status = getHookStatus('/repo/.git/hooks', 'pre-commit');
83
+ expect(status.installed).toBe(true);
84
+ expect(status.managedByGhagga).toBe(true);
85
+ });
86
+ it('returns not managed when external hook exists (no marker)', () => {
87
+ mockExistsSync.mockReturnValue(true);
88
+ mockReadFileSync.mockReturnValue('#!/bin/sh\necho "custom hook"');
89
+ const status = getHookStatus('/repo/.git/hooks', 'commit-msg');
90
+ expect(status.installed).toBe(true);
91
+ expect(status.managedByGhagga).toBe(false);
92
+ expect(status.type).toBe('commit-msg');
93
+ });
94
+ });
95
+ // ─── installHook ────────────────────────────────────────────────
96
+ describe('installHook', () => {
97
+ const hookContent = `#!/bin/sh\n${HOOK_MARKER}\nexec ghagga review`;
98
+ it('creates a new hook file when none exists', () => {
99
+ mockExistsSync.mockReturnValue(false);
100
+ const result = installHook('/repo/.git/hooks', 'pre-commit', hookContent, false);
101
+ expect(result.success).toBe(true);
102
+ expect(result.type).toBe('pre-commit');
103
+ expect(result.message).toContain('Installed pre-commit hook');
104
+ expect(result.backedUp).toBeFalsy();
105
+ expect(mockWriteFileSync).toHaveBeenCalledWith(expect.stringContaining('pre-commit'), hookContent, { mode: 0o755 });
106
+ expect(mockChmodSync).toHaveBeenCalled();
107
+ });
108
+ it('overwrites GHAGGA-managed hooks without --force', () => {
109
+ mockExistsSync.mockReturnValue(true);
110
+ mockReadFileSync.mockReturnValue(`#!/bin/sh\n${HOOK_MARKER}\nold content`);
111
+ const result = installHook('/repo/.git/hooks', 'pre-commit', hookContent, false);
112
+ expect(result.success).toBe(true);
113
+ expect(result.backedUp).toBeFalsy();
114
+ expect(mockWriteFileSync).toHaveBeenCalled();
115
+ // Should NOT have been backed up (renamed)
116
+ expect(mockRenameSync).not.toHaveBeenCalled();
117
+ });
118
+ it('refuses to overwrite external hooks without --force', () => {
119
+ mockExistsSync.mockReturnValue(true);
120
+ mockReadFileSync.mockReturnValue('#!/bin/sh\necho "external"');
121
+ const result = installHook('/repo/.git/hooks', 'pre-commit', hookContent, false);
122
+ expect(result.success).toBe(false);
123
+ expect(result.message).toContain('already exists');
124
+ expect(result.message).toContain('--force');
125
+ expect(mockWriteFileSync).not.toHaveBeenCalled();
126
+ });
127
+ it('backs up external hooks with --force and installs', () => {
128
+ mockExistsSync.mockReturnValue(true);
129
+ mockReadFileSync.mockReturnValue('#!/bin/sh\necho "external"');
130
+ const result = installHook('/repo/.git/hooks', 'pre-commit', hookContent, true);
131
+ expect(result.success).toBe(true);
132
+ expect(result.backedUp).toBe(true);
133
+ expect(result.message).toContain('backed up');
134
+ expect(result.message).toContain('.ghagga-backup');
135
+ expect(mockRenameSync).toHaveBeenCalledWith(expect.stringContaining('pre-commit'), expect.stringContaining('pre-commit.ghagga-backup'));
136
+ expect(mockWriteFileSync).toHaveBeenCalled();
137
+ });
138
+ });
139
+ // ─── uninstallHook ──────────────────────────────────────────────
140
+ describe('uninstallHook', () => {
141
+ it('removes GHAGGA-managed hooks', () => {
142
+ mockExistsSync
143
+ .mockReturnValueOnce(true) // hook exists
144
+ .mockReturnValueOnce(false); // no backup
145
+ mockReadFileSync.mockReturnValue(`#!/bin/sh\n${HOOK_MARKER}\nexec ghagga review`);
146
+ const result = uninstallHook('/repo/.git/hooks', 'pre-commit');
147
+ expect(result.success).toBe(true);
148
+ expect(result.message).toContain('Removed pre-commit hook');
149
+ expect(mockUnlinkSync).toHaveBeenCalled();
150
+ });
151
+ it('skips external hooks (not managed by GHAGGA)', () => {
152
+ mockExistsSync.mockReturnValue(true);
153
+ mockReadFileSync.mockReturnValue('#!/bin/sh\necho "external"');
154
+ const result = uninstallHook('/repo/.git/hooks', 'commit-msg');
155
+ expect(result.success).toBe(false);
156
+ expect(result.message).toContain('not managed by GHAGGA');
157
+ expect(mockUnlinkSync).not.toHaveBeenCalled();
158
+ });
159
+ it('restores backup when present after removing GHAGGA hook', () => {
160
+ mockExistsSync
161
+ .mockReturnValueOnce(true) // hook exists
162
+ .mockReturnValueOnce(true); // backup exists
163
+ mockReadFileSync.mockReturnValue(`#!/bin/sh\n${HOOK_MARKER}\nexec ghagga review`);
164
+ const result = uninstallHook('/repo/.git/hooks', 'pre-commit');
165
+ expect(result.success).toBe(true);
166
+ expect(result.message).toContain('restored previous hook from backup');
167
+ expect(mockUnlinkSync).toHaveBeenCalled();
168
+ expect(mockRenameSync).toHaveBeenCalledWith(expect.stringContaining('.ghagga-backup'), expect.stringContaining('pre-commit'));
169
+ });
170
+ it('handles not-installed case gracefully', () => {
171
+ mockExistsSync.mockReturnValue(false);
172
+ const result = uninstallHook('/repo/.git/hooks', 'pre-commit');
173
+ expect(result.success).toBe(true);
174
+ expect(result.message).toContain('not installed');
175
+ expect(mockUnlinkSync).not.toHaveBeenCalled();
176
+ });
177
+ });
178
+ //# sourceMappingURL=git-hooks.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-hooks.test.js","sourceRoot":"","sources":["../../src/lib/git-hooks.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Git remote utilities for project identification.
3
+ *
4
+ * Resolves the project identifier from the git remote origin URL,
5
+ * normalizing it to "owner/repo" format for memory scoping.
6
+ */
7
+ /**
8
+ * Resolve the project identifier from the git remote origin.
9
+ * Normalizes various URL formats to "owner/repo".
10
+ * Falls back to "local/unknown" if no remote is configured.
11
+ */
12
+ export declare function resolveProjectId(repoPath: string): string;
13
+ /**
14
+ * Get diff of staged files only.
15
+ * Returns an empty string if there are no staged changes or on error.
16
+ */
17
+ export declare function getStagedDiff(repoPath: string): string;
18
+ /**
19
+ * Get list of staged file paths.
20
+ * Returns an empty array if there are no staged files or on error.
21
+ */
22
+ export declare function getStagedFiles(repoPath: string): string[];
23
+ /**
24
+ * Normalize a git remote URL to "owner/repo" format.
25
+ *
26
+ * Handles:
27
+ * https://github.com/owner/repo.git → owner/repo
28
+ * git@github.com:owner/repo.git → owner/repo
29
+ * ssh://git@github.com/owner/repo → owner/repo
30
+ * https://gitlab.com/owner/repo.git → owner/repo
31
+ */
32
+ export declare function normalizeRemoteUrl(url: string): string;
33
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWzD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUtD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAUzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAmBtD"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Git remote utilities for project identification.
3
+ *
4
+ * Resolves the project identifier from the git remote origin URL,
5
+ * normalizing it to "owner/repo" format for memory scoping.
6
+ */
7
+ import { execSync } from 'node:child_process';
8
+ /**
9
+ * Resolve the project identifier from the git remote origin.
10
+ * Normalizes various URL formats to "owner/repo".
11
+ * Falls back to "local/unknown" if no remote is configured.
12
+ */
13
+ export function resolveProjectId(repoPath) {
14
+ try {
15
+ const remoteUrl = execSync('git remote get-url origin', {
16
+ cwd: repoPath,
17
+ encoding: 'utf-8',
18
+ }).trim();
19
+ return normalizeRemoteUrl(remoteUrl);
20
+ }
21
+ catch {
22
+ return 'local/unknown';
23
+ }
24
+ }
25
+ /**
26
+ * Get diff of staged files only.
27
+ * Returns an empty string if there are no staged changes or on error.
28
+ */
29
+ export function getStagedDiff(repoPath) {
30
+ try {
31
+ return execSync('git diff --cached', {
32
+ cwd: repoPath,
33
+ encoding: 'utf-8',
34
+ maxBuffer: 10 * 1024 * 1024,
35
+ });
36
+ }
37
+ catch {
38
+ return '';
39
+ }
40
+ }
41
+ /**
42
+ * Get list of staged file paths.
43
+ * Returns an empty array if there are no staged files or on error.
44
+ */
45
+ export function getStagedFiles(repoPath) {
46
+ try {
47
+ const output = execSync('git diff --cached --name-only', {
48
+ cwd: repoPath,
49
+ encoding: 'utf-8',
50
+ });
51
+ return output.trim().split('\n').filter(Boolean);
52
+ }
53
+ catch {
54
+ return [];
55
+ }
56
+ }
57
+ /**
58
+ * Normalize a git remote URL to "owner/repo" format.
59
+ *
60
+ * Handles:
61
+ * https://github.com/owner/repo.git → owner/repo
62
+ * git@github.com:owner/repo.git → owner/repo
63
+ * ssh://git@github.com/owner/repo → owner/repo
64
+ * https://gitlab.com/owner/repo.git → owner/repo
65
+ */
66
+ export function normalizeRemoteUrl(url) {
67
+ let cleaned = url;
68
+ // Strip .git suffix
69
+ cleaned = cleaned.replace(/\.git$/, '');
70
+ // SSH format: git@host:owner/repo
71
+ const sshMatch = cleaned.match(/^[\w-]+@[\w.-]+:(.+)$/);
72
+ if (sshMatch)
73
+ return sshMatch[1];
74
+ // HTTPS / SSH protocol: extract path after host
75
+ try {
76
+ const parsed = new URL(cleaned);
77
+ // Remove leading slash
78
+ return parsed.pathname.replace(/^\//, '');
79
+ }
80
+ catch {
81
+ // Not a valid URL — return as-is or fallback
82
+ return 'local/unknown';
83
+ }
84
+ }
85
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,QAAQ,CAAC,2BAA2B,EAAE;YACtD,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC,IAAI,EAAE,CAAC;QAEV,OAAO,kBAAkB,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,eAAe,CAAC;IACzB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,mBAAmB,EAAE;YACnC,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,OAAO;YACjB,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;SAC5B,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,+BAA+B,EAAE;YACvD,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,IAAI,OAAO,GAAG,GAAG,CAAC;IAElB,oBAAoB;IACpB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAExC,kCAAkC;IAClC,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACxD,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC,CAAC,CAAE,CAAC;IAElC,gDAAgD;IAChD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QAChC,uBAAuB;QACvB,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,6CAA6C;QAC7C,OAAO,eAAe,CAAC;IACzB,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=git.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.test.d.ts","sourceRoot":"","sources":["../../src/lib/git.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,65 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ // ─── Mocks ──────────────────────────────────────────────────────
3
+ vi.mock('node:child_process', () => ({
4
+ execSync: vi.fn(),
5
+ }));
6
+ import { execSync } from 'node:child_process';
7
+ import { resolveProjectId, normalizeRemoteUrl } from './git.js';
8
+ const mockExecSync = vi.mocked(execSync);
9
+ // ─── Tests ──────────────────────────────────────────────────────
10
+ describe('normalizeRemoteUrl', () => {
11
+ it('normalizes HTTPS URL with .git suffix', () => {
12
+ expect(normalizeRemoteUrl('https://github.com/acme/widgets.git')).toBe('acme/widgets');
13
+ });
14
+ it('normalizes HTTPS URL without .git suffix', () => {
15
+ expect(normalizeRemoteUrl('https://github.com/acme/widgets')).toBe('acme/widgets');
16
+ });
17
+ it('normalizes SSH URL (git@host:owner/repo.git)', () => {
18
+ expect(normalizeRemoteUrl('git@github.com:acme/widgets.git')).toBe('acme/widgets');
19
+ });
20
+ it('normalizes SSH URL without .git suffix', () => {
21
+ expect(normalizeRemoteUrl('git@github.com:acme/widgets')).toBe('acme/widgets');
22
+ });
23
+ it('normalizes ssh:// protocol URL', () => {
24
+ expect(normalizeRemoteUrl('ssh://git@github.com/acme/widgets.git')).toBe('acme/widgets');
25
+ });
26
+ it('normalizes ssh:// protocol URL without .git suffix', () => {
27
+ expect(normalizeRemoteUrl('ssh://git@github.com/acme/widgets')).toBe('acme/widgets');
28
+ });
29
+ it('normalizes GitLab HTTPS URL', () => {
30
+ expect(normalizeRemoteUrl('https://gitlab.com/acme/widgets.git')).toBe('acme/widgets');
31
+ });
32
+ it('normalizes GitLab SSH URL', () => {
33
+ expect(normalizeRemoteUrl('git@gitlab.com:acme/widgets.git')).toBe('acme/widgets');
34
+ });
35
+ it('returns local/unknown for invalid URL', () => {
36
+ expect(normalizeRemoteUrl('not-a-valid-url')).toBe('local/unknown');
37
+ });
38
+ });
39
+ describe('resolveProjectId', () => {
40
+ beforeEach(() => {
41
+ vi.clearAllMocks();
42
+ });
43
+ it('resolves HTTPS remote to owner/repo', () => {
44
+ mockExecSync.mockReturnValue('https://github.com/acme/widgets.git\n');
45
+ expect(resolveProjectId('/path/to/repo')).toBe('acme/widgets');
46
+ expect(mockExecSync).toHaveBeenCalledWith('git remote get-url origin', {
47
+ cwd: '/path/to/repo',
48
+ encoding: 'utf-8',
49
+ });
50
+ });
51
+ it('resolves SSH remote to owner/repo', () => {
52
+ mockExecSync.mockReturnValue('git@github.com:acme/widgets.git\n');
53
+ expect(resolveProjectId('/path/to/repo')).toBe('acme/widgets');
54
+ });
55
+ it('falls back to local/unknown when no remote is configured', () => {
56
+ mockExecSync.mockImplementation(() => { throw new Error('fatal: No such remote'); });
57
+ expect(resolveProjectId('/path/to/repo')).toBe('local/unknown');
58
+ });
59
+ it('passes repoPath as cwd to execSync', () => {
60
+ mockExecSync.mockReturnValue('https://github.com/org/repo.git\n');
61
+ resolveProjectId('/custom/work/dir');
62
+ expect(mockExecSync).toHaveBeenCalledWith('git remote get-url origin', expect.objectContaining({ cwd: '/custom/work/dir' }));
63
+ });
64
+ });
65
+ //# sourceMappingURL=git.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.test.js","sourceRoot":"","sources":["../../src/lib/git.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAE9D,mEAAmE;AAEnE,EAAE,CAAC,IAAI,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC;IACnC,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE;CAClB,CAAC,CAAC,CAAC;AAEJ,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAEhE,MAAM,YAAY,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAEzC,mEAAmE;AAEnE,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,kBAAkB,CAAC,qCAAqC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,kBAAkB,CAAC,iCAAiC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,CAAC,kBAAkB,CAAC,iCAAiC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,CAAC,kBAAkB,CAAC,6BAA6B,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,kBAAkB,CAAC,uCAAuC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,CAAC,kBAAkB,CAAC,mCAAmC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACvF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,kBAAkB,CAAC,qCAAqC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,kBAAkB,CAAC,iCAAiC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,kBAAkB,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,YAAY,CAAC,eAAe,CAAC,uCAAuC,CAAC,CAAC;QAEtE,MAAM,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC/D,MAAM,CAAC,YAAY,CAAC,CAAC,oBAAoB,CAAC,2BAA2B,EAAE;YACrE,GAAG,EAAE,eAAe;YACpB,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,YAAY,CAAC,eAAe,CAAC,mCAAmC,CAAC,CAAC;QAElE,MAAM,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,YAAY,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAErF,MAAM,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,YAAY,CAAC,eAAe,CAAC,mCAAmC,CAAC,CAAC;QAElE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;QAErC,MAAM,CAAC,YAAY,CAAC,CAAC,oBAAoB,CACvC,2BAA2B,EAC3B,MAAM,CAAC,gBAAgB,CAAC,EAAE,GAAG,EAAE,kBAAkB,EAAE,CAAC,CACrD,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Hook script templates for pre-commit and commit-msg hooks.
3
+ *
4
+ * Pure functions that return POSIX shell script strings.
5
+ * Each script includes the GHAGGA marker, a PATH check with
6
+ * graceful degradation, and the appropriate ghagga CLI invocation.
7
+ */
8
+ /** Generate the pre-commit hook script */
9
+ export declare function generatePreCommitHook(extraArgs?: string): string;
10
+ /** Generate the commit-msg hook script */
11
+ export declare function generateCommitMsgHook(extraArgs?: string): string;
12
+ //# sourceMappingURL=hook-templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-templates.d.ts","sourceRoot":"","sources":["../../src/lib/hook-templates.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,0CAA0C;AAC1C,wBAAgB,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAsBhE;AAED,0CAA0C;AAC1C,wBAAgB,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAiBhE"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Hook script templates for pre-commit and commit-msg hooks.
3
+ *
4
+ * Pure functions that return POSIX shell script strings.
5
+ * Each script includes the GHAGGA marker, a PATH check with
6
+ * graceful degradation, and the appropriate ghagga CLI invocation.
7
+ */
8
+ import { HOOK_MARKER } from './hooks-types.js';
9
+ /** Generate the pre-commit hook script */
10
+ export function generatePreCommitHook(extraArgs) {
11
+ const args = extraArgs ? ` ${extraArgs}` : '';
12
+ return `#!/bin/sh
13
+ ${HOOK_MARKER}
14
+ # Installed by: ghagga hooks install
15
+ # To remove: ghagga hooks uninstall
16
+
17
+ # Check if ghagga is available
18
+ if ! command -v ghagga >/dev/null 2>&1; then
19
+ echo "Warning: ghagga not found in PATH. Skipping pre-commit review."
20
+ echo "Install: npm install -g ghagga"
21
+ exit 0
22
+ fi
23
+
24
+ # Check if there are staged changes
25
+ if git diff --cached --quiet; then
26
+ exit 0
27
+ fi
28
+
29
+ # Run review on staged files
30
+ exec ghagga review --staged --plain --exit-on-issues${args}
31
+ `;
32
+ }
33
+ /** Generate the commit-msg hook script */
34
+ export function generateCommitMsgHook(extraArgs) {
35
+ const args = extraArgs ? ` ${extraArgs}` : '';
36
+ return `#!/bin/sh
37
+ ${HOOK_MARKER}
38
+ # Installed by: ghagga hooks install
39
+ # To remove: ghagga hooks uninstall
40
+
41
+ # Check if ghagga is available
42
+ if ! command -v ghagga >/dev/null 2>&1; then
43
+ echo "Warning: ghagga not found in PATH. Skipping commit message review."
44
+ echo "Install: npm install -g ghagga"
45
+ exit 0
46
+ fi
47
+
48
+ # Validate commit message
49
+ exec ghagga review --commit-msg "$1" --plain --exit-on-issues${args}
50
+ `;
51
+ }
52
+ //# sourceMappingURL=hook-templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-templates.js","sourceRoot":"","sources":["../../src/lib/hook-templates.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,0CAA0C;AAC1C,MAAM,UAAU,qBAAqB,CAAC,SAAkB;IACtD,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9C,OAAO;EACP,WAAW;;;;;;;;;;;;;;;;;sDAiByC,IAAI;CACzD,CAAC;AACF,CAAC;AAED,0CAA0C;AAC1C,MAAM,UAAU,qBAAqB,CAAC,SAAkB;IACtD,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9C,OAAO;EACP,WAAW;;;;;;;;;;;;+DAYkD,IAAI;CAClE,CAAC;AACF,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Tests for hook script template generators.
3
+ *
4
+ * Validates that generatePreCommitHook() and generateCommitMsgHook()
5
+ * produce correct POSIX shell scripts with the GHAGGA marker,
6
+ * PATH checks, and appropriate CLI invocations.
7
+ *
8
+ * @see Phase 4, Test 1
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=hook-templates.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-templates.test.d.ts","sourceRoot":"","sources":["../../src/lib/hook-templates.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Tests for hook script template generators.
3
+ *
4
+ * Validates that generatePreCommitHook() and generateCommitMsgHook()
5
+ * produce correct POSIX shell scripts with the GHAGGA marker,
6
+ * PATH checks, and appropriate CLI invocations.
7
+ *
8
+ * @see Phase 4, Test 1
9
+ */
10
+ import { describe, it, expect } from 'vitest';
11
+ import { generatePreCommitHook, generateCommitMsgHook } from './hook-templates.js';
12
+ import { HOOK_MARKER } from './hooks-types.js';
13
+ // ─── pre-commit template ────────────────────────────────────────
14
+ describe('generatePreCommitHook', () => {
15
+ it('starts with #!/bin/sh shebang', () => {
16
+ const script = generatePreCommitHook();
17
+ expect(script.startsWith('#!/bin/sh\n')).toBe(true);
18
+ });
19
+ it('includes the GHAGGA marker comment', () => {
20
+ const script = generatePreCommitHook();
21
+ expect(script).toContain(HOOK_MARKER);
22
+ });
23
+ it('includes the ghagga review --staged command', () => {
24
+ const script = generatePreCommitHook();
25
+ expect(script).toContain('ghagga review --staged --plain --exit-on-issues');
26
+ });
27
+ it('includes PATH check with graceful fallback', () => {
28
+ const script = generatePreCommitHook();
29
+ expect(script).toContain('command -v ghagga');
30
+ expect(script).toContain('ghagga not found in PATH');
31
+ expect(script).toContain('exit 0');
32
+ });
33
+ it('includes empty staged check (git diff --cached --quiet)', () => {
34
+ const script = generatePreCommitHook();
35
+ expect(script).toContain('git diff --cached --quiet');
36
+ });
37
+ it('appends extra args when provided', () => {
38
+ const script = generatePreCommitHook('--quick');
39
+ expect(script).toContain('ghagga review --staged --plain --exit-on-issues --quick');
40
+ });
41
+ it('does not append extra args when not provided', () => {
42
+ const script = generatePreCommitHook();
43
+ // Should end the exec line without trailing args
44
+ expect(script).toContain('exec ghagga review --staged --plain --exit-on-issues\n');
45
+ });
46
+ });
47
+ // ─── commit-msg template ────────────────────────────────────────
48
+ describe('generateCommitMsgHook', () => {
49
+ it('starts with #!/bin/sh shebang', () => {
50
+ const script = generateCommitMsgHook();
51
+ expect(script.startsWith('#!/bin/sh\n')).toBe(true);
52
+ });
53
+ it('includes the GHAGGA marker comment', () => {
54
+ const script = generateCommitMsgHook();
55
+ expect(script).toContain(HOOK_MARKER);
56
+ });
57
+ it('includes the ghagga review --commit-msg command', () => {
58
+ const script = generateCommitMsgHook();
59
+ expect(script).toContain('ghagga review --commit-msg "$1" --plain --exit-on-issues');
60
+ });
61
+ it('includes PATH check with graceful fallback', () => {
62
+ const script = generateCommitMsgHook();
63
+ expect(script).toContain('command -v ghagga');
64
+ expect(script).toContain('ghagga not found in PATH');
65
+ expect(script).toContain('exit 0');
66
+ });
67
+ it('appends extra args when provided', () => {
68
+ const script = generateCommitMsgHook('--quick');
69
+ expect(script).toContain('ghagga review --commit-msg "$1" --plain --exit-on-issues --quick');
70
+ });
71
+ it('does not append extra args when not provided', () => {
72
+ const script = generateCommitMsgHook();
73
+ expect(script).toContain('exec ghagga review --commit-msg "$1" --plain --exit-on-issues\n');
74
+ });
75
+ });
76
+ //# sourceMappingURL=hook-templates.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-templates.test.js","sourceRoot":"","sources":["../../src/lib/hook-templates.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Hook-related type definitions for the GHAGGA CLI.
3
+ *
4
+ * Used by git-hooks utilities, hook templates, and the hooks
5
+ * command group (install, uninstall, status).
6
+ */
7
+ /** Marker comment identifying GHAGGA-managed hooks */
8
+ export declare const HOOK_MARKER = "# GHAGGA-MANAGED-HOOK \u2014 do not edit";
9
+ /** Supported git hook types */
10
+ export type HookType = 'pre-commit' | 'commit-msg';
11
+ /** Result of a hook status check */
12
+ export interface HookStatus {
13
+ type: HookType;
14
+ installed: boolean;
15
+ managedByGhagga: boolean;
16
+ path: string;
17
+ }
18
+ /** Options for hook installation */
19
+ export interface HookInstallOptions {
20
+ force?: boolean;
21
+ }
22
+ /** Result of install/uninstall operations */
23
+ export interface HookOperationResult {
24
+ type: HookType;
25
+ success: boolean;
26
+ message: string;
27
+ /** Previous hook content if backed up */
28
+ backedUp?: boolean;
29
+ }
30
+ //# sourceMappingURL=hooks-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks-types.d.ts","sourceRoot":"","sources":["../../src/lib/hooks-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,sDAAsD;AACtD,eAAO,MAAM,WAAW,6CAAwC,CAAC;AAEjE,+BAA+B;AAC/B,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,YAAY,CAAC;AAEnD,oCAAoC;AACpC,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,oCAAoC;AACpC,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,6CAA6C;AAC7C,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Hook-related type definitions for the GHAGGA CLI.
3
+ *
4
+ * Used by git-hooks utilities, hook templates, and the hooks
5
+ * command group (install, uninstall, status).
6
+ */
7
+ /** Marker comment identifying GHAGGA-managed hooks */
8
+ export const HOOK_MARKER = '# GHAGGA-MANAGED-HOOK — do not edit';
9
+ //# sourceMappingURL=hooks-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks-types.js","sourceRoot":"","sources":["../../src/lib/hooks-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,sDAAsD;AACtD,MAAM,CAAC,MAAM,WAAW,GAAG,qCAAqC,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * OAuth device flow tests.
3
+ *
4
+ * Tests requestDeviceCode(), pollForAccessToken(), and fetchGitHubUser()
5
+ * with mocked global fetch and fake timers for the polling loop.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=oauth.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.test.d.ts","sourceRoot":"","sources":["../../src/lib/oauth.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}