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
package/dist/index.js CHANGED
@@ -12,12 +12,16 @@
12
12
  * You can override with --provider, --model, --api-key for other providers.
13
13
  *
14
14
  * Environment variables (override stored config):
15
- * GHAGGA_API_KEY API key for the LLM provider
16
- * GHAGGA_PROVIDER LLM provider: anthropic, openai, google, github, ollama
17
- * GHAGGA_MODEL Model identifier
18
- * GITHUB_TOKEN GitHub token (fallback for github provider)
15
+ * GHAGGA_API_KEY API key for the LLM provider
16
+ * GHAGGA_PROVIDER LLM provider: anthropic, openai, google, github, ollama, qwen
17
+ * GHAGGA_MODEL Model identifier
18
+ * GITHUB_TOKEN GitHub token (fallback for github provider)
19
+ * GHAGGA_MEMORY_BACKEND Memory backend: sqlite (default) or engram
19
20
  */
20
21
  import 'dotenv/config';
22
+ import { readFileSync } from 'node:fs';
23
+ import { fileURLToPath } from 'node:url';
24
+ import { dirname, resolve } from 'node:path';
21
25
  import { Command } from 'commander';
22
26
  import { DEFAULT_MODELS } from 'ghagga-core';
23
27
  import { loadConfig, getStoredToken } from './lib/config.js';
@@ -25,11 +29,23 @@ import { reviewCommand } from './commands/review.js';
25
29
  import { loginCommand } from './commands/login.js';
26
30
  import { logoutCommand } from './commands/logout.js';
27
31
  import { statusCommand } from './commands/status.js';
32
+ import { memoryCommand } from './commands/memory/index.js';
33
+ import { hooksCommand } from './commands/hooks/index.js';
34
+ import * as tui from './ui/tui.js';
35
+ // Read version from package.json at runtime (no hardcoded strings)
36
+ const __dirname = dirname(fileURLToPath(import.meta.url));
37
+ const pkg = JSON.parse(readFileSync(resolve(__dirname, '..', 'package.json'), 'utf-8'));
28
38
  const program = new Command();
29
39
  program
30
40
  .name('ghagga')
31
41
  .description('AI-powered code review CLI')
32
- .version('2.0.0');
42
+ .version(pkg.version)
43
+ .option('--plain', 'Disable styled terminal output');
44
+ // Initialize TUI mode before any command runs (Design AD3)
45
+ program.hook('preAction', (thisCommand) => {
46
+ const opts = thisCommand.optsWithGlobals();
47
+ tui.init({ plain: opts.plain });
48
+ });
33
49
  // ─── Login ──────────────────────────────────────────────────────
34
50
  program
35
51
  .command('login')
@@ -64,8 +80,14 @@ program
64
80
  .option('--no-semgrep', 'Disable Semgrep static analysis')
65
81
  .option('--no-trivy', 'Disable Trivy vulnerability scanning')
66
82
  .option('--no-cpd', 'Disable CPD duplicate detection')
83
+ .option('--no-memory', 'Disable review memory')
67
84
  .option('-c, --config <path>', 'Path to .ghagga.json config file')
68
85
  .option('-v, --verbose', 'Show detailed progress during review')
86
+ .option('--staged', 'Review only staged changes (for pre-commit hooks)')
87
+ .option('--commit-msg <file>', 'Validate commit message from file path')
88
+ .option('--exit-on-issues', 'Exit with code 1 if critical/high issues found')
89
+ .option('--quick', 'Static analysis only — skip LLM review')
90
+ .option('--memory-backend <type>', 'Memory backend: sqlite (default) or engram (env: GHAGGA_MEMORY_BACKEND)', 'sqlite')
69
91
  .action(async (path, options) => {
70
92
  // ── Auto-resolve auth from stored config ──────────────────
71
93
  const config = loadConfig();
@@ -86,27 +108,27 @@ program
86
108
  // ── Validate mode ─────────────────────────────────────────
87
109
  const validModes = ['simple', 'workflow', 'consensus'];
88
110
  if (!validModes.includes(options.mode)) {
89
- console.error(`\u274c Invalid mode "${options.mode}". Choose from: ${validModes.join(', ')}`);
111
+ tui.log.error(`❌ Invalid mode "${options.mode}". Choose from: ${validModes.join(', ')}`);
90
112
  process.exit(1);
91
113
  }
92
114
  // ── Validate provider ─────────────────────────────────────
93
- const validProviders = ['anthropic', 'openai', 'google', 'github', 'ollama'];
115
+ const validProviders = ['anthropic', 'openai', 'google', 'github', 'ollama', 'qwen'];
94
116
  if (!validProviders.includes(options.provider)) {
95
- console.error(`\u274c Invalid provider "${options.provider}". Choose from: ${validProviders.join(', ')}`);
117
+ tui.log.error(`❌ Invalid provider "${options.provider}". Choose from: ${validProviders.join(', ')}`);
96
118
  process.exit(1);
97
119
  }
98
120
  // ── Validate format ───────────────────────────────────────
99
121
  const validFormats = ['markdown', 'json'];
100
122
  if (!validFormats.includes(options.format)) {
101
- console.error(`\u274c Invalid format "${options.format}". Choose from: ${validFormats.join(', ')}`);
123
+ tui.log.error(`❌ Invalid format "${options.format}". Choose from: ${validFormats.join(', ')}`);
102
124
  process.exit(1);
103
125
  }
104
- // ── Validate API key (not required for ollama) ─────────────
105
- if (!options.apiKey && options.provider !== 'ollama') {
106
- console.error('\u274c No API key available.\n');
107
- console.error(' Quick fix: run "ghagga login" to authenticate with GitHub (free!)');
108
- console.error(' Or pass --api-key <key> or set GHAGGA_API_KEY.');
109
- console.error(' Or use --provider ollama for local models (no key needed).\n');
126
+ // ── Validate API key (not required for ollama or --quick mode) ──
127
+ if (!options.apiKey && options.provider !== 'ollama' && !options.quick) {
128
+ tui.log.error(' No API key available.\n');
129
+ tui.log.error(' Quick fix: run "ghagga login" to authenticate with GitHub (free!)');
130
+ tui.log.error(' Or pass --api-key <key> or set GHAGGA_API_KEY.');
131
+ tui.log.error(' Or use --provider ollama for local models (no key needed).\n');
110
132
  process.exit(1);
111
133
  }
112
134
  // Ollama doesn't need an API key — use a placeholder
@@ -120,14 +142,24 @@ program
120
142
  mode: options.mode,
121
143
  provider,
122
144
  model,
123
- apiKey: options.apiKey,
145
+ apiKey: options.apiKey ?? '',
124
146
  format: options.format,
125
147
  semgrep: options.semgrep,
126
148
  trivy: options.trivy,
127
149
  cpd: options.cpd,
150
+ memory: options.memory,
151
+ memoryBackend: options.memoryBackend,
128
152
  config: options.config,
129
153
  verbose: options.verbose ?? false,
154
+ staged: options.staged ?? false,
155
+ commitMsg: options.commitMsg,
156
+ exitOnIssues: options.exitOnIssues ?? false,
157
+ quick: options.quick ?? false,
130
158
  });
131
159
  });
160
+ // ─── Memory ─────────────────────────────────────────────────────
161
+ program.addCommand(memoryCommand);
162
+ // ─── Hooks ──────────────────────────────────────────────────────
163
+ program.addCommand(hooksCommand);
132
164
  program.parse();
133
165
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,7 @@ export interface GhaggaCliConfig {
14
14
  /** Default model for the provider */
15
15
  defaultModel?: string;
16
16
  }
17
+ export declare function getConfigDir(): string;
17
18
  /**
18
19
  * Load the CLI config file. Returns empty config if not found.
19
20
  */
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,MAAM,WAAW,eAAe;IAC9B,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,2BAA2B;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAgBD;;GAEG;AACH,wBAAgB,UAAU,IAAI,eAAe,CAa5C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CASxD;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAGpC;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAG9C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,MAAM,WAAW,eAAe;IAC9B,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,2BAA2B;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAID,wBAAgB,YAAY,IAAI,MAAM,CAIrC;AAQD;;GAEG;AACH,wBAAgB,UAAU,IAAI,eAAe,CAa5C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CASxD;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAGpC;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAG9C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
@@ -8,7 +8,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
8
8
  import { join } from 'node:path';
9
9
  import { homedir } from 'node:os';
10
10
  // ─── Paths ──────────────────────────────────────────────────────
11
- function getConfigDir() {
11
+ export function getConfigDir() {
12
12
  const xdgConfig = process.env['XDG_CONFIG_HOME'];
13
13
  const base = xdgConfig || join(homedir(), '.config');
14
14
  return join(base, 'ghagga');
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAkBlC,mEAAmE;AAEnE,SAAS,YAAY;IACnB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,SAAS,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IACrD,OAAO,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,aAAa;IACpB,OAAO,IAAI,CAAC,YAAY,EAAE,EAAE,aAAa,CAAC,CAAC;AAC7C,CAAC;AAED,mEAAmE;AAEnE;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IAEnC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAuB;IAChD,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IACjC,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IAEnC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AAC7E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,UAAU,CAAC,EAAE,CAAC,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,aAAa,EAAE,CAAC;AACzB,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAkBlC,mEAAmE;AAEnE,MAAM,UAAU,YAAY;IAC1B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,SAAS,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IACrD,OAAO,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,aAAa;IACpB,OAAO,IAAI,CAAC,YAAY,EAAE,EAAE,aAAa,CAAC,CAAC;AAC7C,CAAC;AAED,mEAAmE;AAEnE;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IAEnC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAuB;IAChD,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IACjC,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IAEnC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AAC7E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,UAAU,CAAC,EAAE,CAAC,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,aAAa,EAAE,CAAC;AACzB,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Tests for CLI configuration management.
3
+ *
4
+ * Mocks node:fs and node:os to isolate file system operations.
5
+ * Validates loadConfig, saveConfig, clearConfig, isLoggedIn,
6
+ * getStoredToken, and getConfigFilePath.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.d.ts","sourceRoot":"","sources":["../../src/lib/config.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Tests for CLI configuration management.
3
+ *
4
+ * Mocks node:fs and node:os to isolate file system operations.
5
+ * Validates loadConfig, saveConfig, clearConfig, isLoggedIn,
6
+ * getStoredToken, and getConfigFilePath.
7
+ */
8
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
9
+ // ─── Mocks ─────────────────────────────────────────────────────
10
+ vi.mock('node:fs', () => ({
11
+ existsSync: vi.fn(),
12
+ mkdirSync: vi.fn(),
13
+ readFileSync: vi.fn(),
14
+ writeFileSync: vi.fn(),
15
+ }));
16
+ vi.mock('node:os', () => ({
17
+ homedir: vi.fn().mockReturnValue('/mock-home'),
18
+ }));
19
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
20
+ import { homedir } from 'node:os';
21
+ import { loadConfig, saveConfig, clearConfig, isLoggedIn, getStoredToken, getConfigFilePath, } from './config.js';
22
+ const mockExistsSync = vi.mocked(existsSync);
23
+ const mockMkdirSync = vi.mocked(mkdirSync);
24
+ const mockReadFileSync = vi.mocked(readFileSync);
25
+ const mockWriteFileSync = vi.mocked(writeFileSync);
26
+ const mockHomedir = vi.mocked(homedir);
27
+ // ─── Setup ─────────────────────────────────────────────────────
28
+ beforeEach(() => {
29
+ vi.clearAllMocks();
30
+ mockHomedir.mockReturnValue('/mock-home');
31
+ // Clear XDG override so getConfigDir uses homedir()
32
+ delete process.env['XDG_CONFIG_HOME'];
33
+ });
34
+ afterEach(() => {
35
+ delete process.env['XDG_CONFIG_HOME'];
36
+ });
37
+ // ─── loadConfig ────────────────────────────────────────────────
38
+ describe('loadConfig', () => {
39
+ it('should return empty object when config file does not exist', () => {
40
+ mockExistsSync.mockReturnValue(false);
41
+ const config = loadConfig();
42
+ expect(config).toEqual({});
43
+ expect(mockExistsSync).toHaveBeenCalledWith(expect.stringContaining('config.json'));
44
+ });
45
+ it('should parse and return valid JSON config', () => {
46
+ const stored = { githubToken: 'gho_abc123', githubLogin: 'testuser' };
47
+ mockExistsSync.mockReturnValue(true);
48
+ mockReadFileSync.mockReturnValue(JSON.stringify(stored));
49
+ const config = loadConfig();
50
+ expect(config).toEqual(stored);
51
+ expect(mockReadFileSync).toHaveBeenCalledWith(expect.stringContaining('config.json'), 'utf-8');
52
+ });
53
+ it('should return empty object when file contains invalid JSON', () => {
54
+ mockExistsSync.mockReturnValue(true);
55
+ mockReadFileSync.mockReturnValue('{ broken json!!!');
56
+ const config = loadConfig();
57
+ expect(config).toEqual({});
58
+ });
59
+ it('should return empty object when readFileSync throws', () => {
60
+ mockExistsSync.mockReturnValue(true);
61
+ mockReadFileSync.mockImplementation(() => {
62
+ throw new Error('EACCES: permission denied');
63
+ });
64
+ const config = loadConfig();
65
+ expect(config).toEqual({});
66
+ });
67
+ it('should use XDG_CONFIG_HOME when set', () => {
68
+ process.env['XDG_CONFIG_HOME'] = '/custom/config';
69
+ mockExistsSync.mockReturnValue(false);
70
+ loadConfig();
71
+ expect(mockExistsSync).toHaveBeenCalledWith(expect.stringContaining('/custom/config/ghagga/config.json'));
72
+ });
73
+ it('should use homedir/.config when XDG_CONFIG_HOME is not set', () => {
74
+ mockExistsSync.mockReturnValue(false);
75
+ loadConfig();
76
+ expect(mockExistsSync).toHaveBeenCalledWith(expect.stringContaining('/mock-home/.config/ghagga/config.json'));
77
+ });
78
+ });
79
+ // ─── saveConfig ────────────────────────────────────────────────
80
+ describe('saveConfig', () => {
81
+ it('should create config directory if it does not exist', () => {
82
+ mockExistsSync.mockReturnValue(false);
83
+ saveConfig({ githubToken: 'gho_token' });
84
+ expect(mockMkdirSync).toHaveBeenCalledWith(expect.stringContaining('ghagga'), { recursive: true });
85
+ });
86
+ it('should not create directory if it already exists', () => {
87
+ mockExistsSync.mockReturnValue(true);
88
+ saveConfig({ githubToken: 'gho_token' });
89
+ expect(mockMkdirSync).not.toHaveBeenCalled();
90
+ });
91
+ it('should write JSON with 2-space indent and trailing newline', () => {
92
+ mockExistsSync.mockReturnValue(true);
93
+ const config = { githubToken: 'gho_abc', githubLogin: 'user' };
94
+ saveConfig(config);
95
+ expect(mockWriteFileSync).toHaveBeenCalledWith(expect.stringContaining('config.json'), JSON.stringify(config, null, 2) + '\n', 'utf-8');
96
+ });
97
+ it('should save empty config object', () => {
98
+ mockExistsSync.mockReturnValue(true);
99
+ saveConfig({});
100
+ expect(mockWriteFileSync).toHaveBeenCalledWith(expect.stringContaining('config.json'), '{}\n', 'utf-8');
101
+ });
102
+ it('should save all optional fields when provided', () => {
103
+ mockExistsSync.mockReturnValue(true);
104
+ const config = {
105
+ githubToken: 'gho_tok',
106
+ githubLogin: 'user',
107
+ defaultProvider: 'anthropic',
108
+ defaultModel: 'claude-sonnet-4-20250514',
109
+ };
110
+ saveConfig(config);
111
+ const writtenJson = mockWriteFileSync.mock.calls[0][1];
112
+ const parsed = JSON.parse(writtenJson);
113
+ expect(parsed).toEqual(config);
114
+ });
115
+ });
116
+ // ─── clearConfig ───────────────────────────────────────────────
117
+ describe('clearConfig', () => {
118
+ it('should save an empty object', () => {
119
+ // existsSync is called twice: once for dir check, once for config path
120
+ // In saveConfig, existsSync is called for the dir
121
+ mockExistsSync.mockReturnValue(true);
122
+ clearConfig();
123
+ expect(mockWriteFileSync).toHaveBeenCalledWith(expect.stringContaining('config.json'), '{}\n', 'utf-8');
124
+ });
125
+ });
126
+ // ─── isLoggedIn ────────────────────────────────────────────────
127
+ describe('isLoggedIn', () => {
128
+ it('should return true when githubToken exists', () => {
129
+ mockExistsSync.mockReturnValue(true);
130
+ mockReadFileSync.mockReturnValue(JSON.stringify({ githubToken: 'gho_valid' }));
131
+ expect(isLoggedIn()).toBe(true);
132
+ });
133
+ it('should return false when githubToken is missing', () => {
134
+ mockExistsSync.mockReturnValue(true);
135
+ mockReadFileSync.mockReturnValue(JSON.stringify({ githubLogin: 'user' }));
136
+ expect(isLoggedIn()).toBe(false);
137
+ });
138
+ it('should return false when config file does not exist', () => {
139
+ mockExistsSync.mockReturnValue(false);
140
+ expect(isLoggedIn()).toBe(false);
141
+ });
142
+ it('should return false when githubToken is empty string', () => {
143
+ mockExistsSync.mockReturnValue(true);
144
+ mockReadFileSync.mockReturnValue(JSON.stringify({ githubToken: '' }));
145
+ expect(isLoggedIn()).toBe(false);
146
+ });
147
+ });
148
+ // ─── getStoredToken ────────────────────────────────────────────
149
+ describe('getStoredToken', () => {
150
+ it('should return the token when present', () => {
151
+ mockExistsSync.mockReturnValue(true);
152
+ mockReadFileSync.mockReturnValue(JSON.stringify({ githubToken: 'gho_secret123' }));
153
+ expect(getStoredToken()).toBe('gho_secret123');
154
+ });
155
+ it('should return null when token is missing', () => {
156
+ mockExistsSync.mockReturnValue(true);
157
+ mockReadFileSync.mockReturnValue(JSON.stringify({}));
158
+ expect(getStoredToken()).toBeNull();
159
+ });
160
+ it('should return null when config file does not exist', () => {
161
+ mockExistsSync.mockReturnValue(false);
162
+ expect(getStoredToken()).toBeNull();
163
+ });
164
+ });
165
+ // ─── getConfigFilePath ─────────────────────────────────────────
166
+ describe('getConfigFilePath', () => {
167
+ it('should return path ending with ghagga/config.json', () => {
168
+ const path = getConfigFilePath();
169
+ expect(path).toMatch(/ghagga[/\\]config\.json$/);
170
+ });
171
+ it('should use homedir base path', () => {
172
+ const path = getConfigFilePath();
173
+ expect(path).toContain('/mock-home/.config/ghagga');
174
+ });
175
+ it('should respect XDG_CONFIG_HOME', () => {
176
+ process.env['XDG_CONFIG_HOME'] = '/xdg/path';
177
+ const path = getConfigFilePath();
178
+ expect(path).toContain('/xdg/path/ghagga');
179
+ });
180
+ });
181
+ //# sourceMappingURL=config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.js","sourceRoot":"","sources":["../../src/lib/config.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Git hook utilities for install, uninstall, and status operations.
3
+ *
4
+ * Handles detection of the hooks directory (respects core.hooksPath),
5
+ * GHAGGA marker detection, hook installation with backup, and
6
+ * clean uninstallation with backup restoration.
7
+ */
8
+ import { type HookType, type HookStatus, type HookOperationResult } from './hooks-types.js';
9
+ /** Get the git hooks directory (respects core.hooksPath config) */
10
+ export declare function getHooksDir(): string;
11
+ /** Check if we're in a git repository */
12
+ export declare function isGitRepo(): boolean;
13
+ /** Get the status of a specific hook */
14
+ export declare function getHookStatus(hooksDir: string, hookType: HookType): HookStatus;
15
+ /** Install a hook script */
16
+ export declare function installHook(hooksDir: string, hookType: HookType, content: string, force: boolean): HookOperationResult;
17
+ /** Uninstall a hook if it's managed by GHAGGA */
18
+ export declare function uninstallHook(hooksDir: string, hookType: HookType): HookOperationResult;
19
+ //# sourceMappingURL=git-hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-hooks.d.ts","sourceRoot":"","sources":["../../src/lib/git-hooks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,EAAe,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEzG,mEAAmE;AACnE,wBAAgB,WAAW,IAAI,MAAM,CAYpC;AAED,yCAAyC;AACzC,wBAAgB,SAAS,IAAI,OAAO,CAOnC;AAED,wCAAwC;AACxC,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,UAAU,CAoB9E;AAED,4BAA4B;AAC5B,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,GACb,mBAAmB,CAmCrB;AAED,iDAAiD;AACjD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,mBAAmB,CAsCvF"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Git hook utilities for install, uninstall, and status operations.
3
+ *
4
+ * Handles detection of the hooks directory (respects core.hooksPath),
5
+ * GHAGGA marker detection, hook installation with backup, and
6
+ * clean uninstallation with backup restoration.
7
+ */
8
+ import { existsSync, readFileSync, writeFileSync, unlinkSync, renameSync, chmodSync } from 'node:fs';
9
+ import { join } from 'node:path';
10
+ import { execSync } from 'node:child_process';
11
+ import { HOOK_MARKER } from './hooks-types.js';
12
+ /** Get the git hooks directory (respects core.hooksPath config) */
13
+ export function getHooksDir() {
14
+ // Try core.hooksPath first
15
+ try {
16
+ const hooksPath = execSync('git config core.hooksPath', { encoding: 'utf-8' }).trim();
17
+ if (hooksPath)
18
+ return hooksPath;
19
+ }
20
+ catch {
21
+ // Not set, use default
22
+ }
23
+ // Default: .git/hooks
24
+ const gitDir = execSync('git rev-parse --git-dir', { encoding: 'utf-8' }).trim();
25
+ return join(gitDir, 'hooks');
26
+ }
27
+ /** Check if we're in a git repository */
28
+ export function isGitRepo() {
29
+ try {
30
+ execSync('git rev-parse --git-dir', { stdio: 'pipe' });
31
+ return true;
32
+ }
33
+ catch {
34
+ return false;
35
+ }
36
+ }
37
+ /** Get the status of a specific hook */
38
+ export function getHookStatus(hooksDir, hookType) {
39
+ const hookPath = join(hooksDir, hookType);
40
+ const exists = existsSync(hookPath);
41
+ let managedByGhagga = false;
42
+ if (exists) {
43
+ try {
44
+ const content = readFileSync(hookPath, 'utf-8');
45
+ managedByGhagga = content.includes(HOOK_MARKER);
46
+ }
47
+ catch {
48
+ // Can't read, not managed
49
+ }
50
+ }
51
+ return {
52
+ type: hookType,
53
+ installed: exists,
54
+ managedByGhagga,
55
+ path: hookPath,
56
+ };
57
+ }
58
+ /** Install a hook script */
59
+ export function installHook(hooksDir, hookType, content, force) {
60
+ const hookPath = join(hooksDir, hookType);
61
+ const exists = existsSync(hookPath);
62
+ let backedUp = false;
63
+ if (exists) {
64
+ const existing = readFileSync(hookPath, 'utf-8');
65
+ if (existing.includes(HOOK_MARKER)) {
66
+ // Already GHAGGA-managed, overwrite
67
+ }
68
+ else if (!force) {
69
+ return {
70
+ type: hookType,
71
+ success: false,
72
+ message: `Hook ${hookType} already exists (not managed by GHAGGA). Use --force to overwrite.`,
73
+ };
74
+ }
75
+ else {
76
+ // Backup existing hook
77
+ const backupPath = `${hookPath}.ghagga-backup`;
78
+ renameSync(hookPath, backupPath);
79
+ backedUp = true;
80
+ }
81
+ }
82
+ writeFileSync(hookPath, content, { mode: 0o755 });
83
+ // Also chmod explicitly for systems where writeFileSync mode doesn't work
84
+ chmodSync(hookPath, 0o755);
85
+ return {
86
+ type: hookType,
87
+ success: true,
88
+ message: backedUp
89
+ ? `Installed ${hookType} hook (existing hook backed up to ${hookType}.ghagga-backup)`
90
+ : `Installed ${hookType} hook`,
91
+ backedUp,
92
+ };
93
+ }
94
+ /** Uninstall a hook if it's managed by GHAGGA */
95
+ export function uninstallHook(hooksDir, hookType) {
96
+ const hookPath = join(hooksDir, hookType);
97
+ if (!existsSync(hookPath)) {
98
+ return {
99
+ type: hookType,
100
+ success: true,
101
+ message: `Hook ${hookType} not installed, nothing to remove`,
102
+ };
103
+ }
104
+ const content = readFileSync(hookPath, 'utf-8');
105
+ if (!content.includes(HOOK_MARKER)) {
106
+ return {
107
+ type: hookType,
108
+ success: false,
109
+ message: `Hook ${hookType} exists but is not managed by GHAGGA. Skipping.`,
110
+ };
111
+ }
112
+ unlinkSync(hookPath);
113
+ // Restore backup if exists
114
+ const backupPath = `${hookPath}.ghagga-backup`;
115
+ if (existsSync(backupPath)) {
116
+ renameSync(backupPath, hookPath);
117
+ return {
118
+ type: hookType,
119
+ success: true,
120
+ message: `Removed ${hookType} hook (restored previous hook from backup)`,
121
+ };
122
+ }
123
+ return {
124
+ type: hookType,
125
+ success: true,
126
+ message: `Removed ${hookType} hook`,
127
+ };
128
+ }
129
+ //# sourceMappingURL=git-hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-hooks.js","sourceRoot":"","sources":["../../src/lib/git-hooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
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
+ export {};
11
+ //# sourceMappingURL=git-hooks.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-hooks.test.d.ts","sourceRoot":"","sources":["../../src/lib/git-hooks.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}