@commitguard/cli 0.0.14 → 0.0.16

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 (2) hide show
  1. package/dist/index.mjs +269 -287
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -3,12 +3,12 @@ import process from "node:process";
3
3
  import { consola } from "consola";
4
4
  import updateNotifier from "update-notifier";
5
5
  import { execFileSync, execSync } from "node:child_process";
6
+ import { createHash } from "node:crypto";
7
+ import { cancel, confirm, intro, isCancel, log, multiselect, note, outro, text } from "@clack/prompts";
8
+ import { Entry } from "@napi-rs/keyring";
6
9
  import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
7
10
  import { homedir } from "node:os";
8
11
  import { dirname, join } from "node:path";
9
- import { cancel, confirm, intro, isCancel, log, multiselect, note, outro, select, text } from "@clack/prompts";
10
- import { createHash } from "node:crypto";
11
- import { Entry } from "@napi-rs/keyring";
12
12
  import { fileURLToPath, pathToFileURL } from "node:url";
13
13
  import { readFile } from "node:fs/promises";
14
14
  import { findUp } from "find-up";
@@ -17,7 +17,7 @@ import stringWidth from "string-width";
17
17
  import "dotenv/config";
18
18
 
19
19
  //#region package.json
20
- var version = "0.0.14";
20
+ var version = "0.0.16";
21
21
  var package_default = {
22
22
  name: "@commitguard/cli",
23
23
  type: "module",
@@ -68,279 +68,8 @@ var package_default = {
68
68
  "tsdown": "^0.18.3",
69
69
  "typescript": "^5.9.3",
70
70
  "vitest": "^4.0.16"
71
- }
72
- };
73
-
74
- //#endregion
75
- //#region src/utils/global.ts
76
- function createDiffHash(diff) {
77
- return createHash("md5").update(diff).digest("base64url");
78
- }
79
- function addGitLineNumbers(diff) {
80
- if (!diff.trim()) return diff;
81
- const lines = diff.split("\n");
82
- const result = [];
83
- let oldLine = 0;
84
- let newLine = 0;
85
- for (const line of lines) if (line.startsWith("@@")) {
86
- const match = line.match(/@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
87
- if (match) {
88
- oldLine = Number.parseInt(match[1], 10);
89
- newLine = Number.parseInt(match[2], 10);
90
- }
91
- result.push(line);
92
- } else if (line.startsWith("---") || line.startsWith("+++") || line.startsWith("diff ") || line.startsWith("index ")) result.push(line);
93
- else if (line.startsWith("-")) {
94
- result.push(`${oldLine}:${line}`);
95
- oldLine++;
96
- } else if (line.startsWith("+")) {
97
- result.push(`${newLine}:${line}`);
98
- newLine++;
99
- } else {
100
- result.push(`${newLine}:${line}`);
101
- oldLine++;
102
- newLine++;
103
- }
104
- return result.join("\n");
105
- }
106
- const MESSAGES = { noGit: "No .git folder found. Run this inside a git repository." };
107
-
108
- //#endregion
109
- //#region src/utils/config.ts
110
- const MAX_CUSTOM_PROMPT_LENGTH = 500;
111
- const CONFIG_DIR = join(homedir(), ".commitguard");
112
- const PROJECTS_CONFIG_PATH = join(CONFIG_DIR, "projects.json");
113
- let projectsConfigCache = null;
114
- const GIT_DIR$1 = ".git";
115
- function ensureConfigDir() {
116
- if (!existsSync(CONFIG_DIR)) try {
117
- mkdirSync(CONFIG_DIR, { recursive: true });
118
- } catch (e) {
119
- consola.error(`Failed to create config directory at ${CONFIG_DIR}: ${e.message}`);
120
- }
121
- }
122
- function getDefaultConfig() {
123
- return {
124
- context: "normal",
125
- checks: {
126
- security: true,
127
- performance: true,
128
- codeQuality: true,
129
- architecture: true
130
- },
131
- severityLevels: {
132
- critical: true,
133
- warning: true,
134
- suggestion: false
135
- },
136
- customRule: ""
137
- };
138
- }
139
- let projectIdCache = null;
140
- function getProjectId() {
141
- if (projectIdCache) return projectIdCache;
142
- try {
143
- projectIdCache = execFileSync("git", [
144
- "rev-list",
145
- "--max-parents=0",
146
- "HEAD"
147
- ], {
148
- encoding: "utf8",
149
- stdio: [
150
- "pipe",
151
- "pipe",
152
- "ignore"
153
- ]
154
- }).trim().split("\n")[0];
155
- return projectIdCache;
156
- } catch {
157
- consola.error("Warning: Unable to determine project ID. Using current working directory as fallback project ID.");
158
- projectIdCache = process.cwd();
159
- return projectIdCache;
160
- }
161
- }
162
- function loadProjectsConfig() {
163
- if (projectsConfigCache) return projectsConfigCache;
164
- if (existsSync(PROJECTS_CONFIG_PATH)) try {
165
- const content = readFileSync(PROJECTS_CONFIG_PATH, "utf8");
166
- projectsConfigCache = JSON.parse(content);
167
- return projectsConfigCache;
168
- } catch {
169
- consola.warn("Failed to parse projects config");
170
- }
171
- projectsConfigCache = {};
172
- return projectsConfigCache;
173
- }
174
- function saveProjectsConfig(projects) {
175
- try {
176
- ensureConfigDir();
177
- writeFileSync(PROJECTS_CONFIG_PATH, JSON.stringify(projects, null, 2));
178
- projectsConfigCache = projects;
179
- } catch (e) {
180
- consola.error(`Failed to save projects config: ${e.message}`);
181
- }
182
- }
183
- function loadConfig() {
184
- const projectId = getProjectId();
185
- return loadProjectsConfig()[projectId] || getDefaultConfig();
186
- }
187
- async function manageConfig() {
188
- if (!existsSync(GIT_DIR$1)) {
189
- cancel(MESSAGES.noGit);
190
- return;
191
- }
192
- const projectId = getProjectId();
193
- const currentConfig = loadConfig();
194
- intro(`CommitGuard Configuration`);
195
- const enabledChecks = await multiselect({
196
- message: "Select enabled checks for this project:",
197
- options: [
198
- {
199
- value: "security",
200
- label: "Security"
201
- },
202
- {
203
- value: "performance",
204
- label: "Performance"
205
- },
206
- {
207
- value: "codeQuality",
208
- label: "Code Quality"
209
- },
210
- {
211
- value: "architecture",
212
- label: "Architecture"
213
- }
214
- ],
215
- initialValues: Object.entries(currentConfig.checks).filter(([_, enabled]) => enabled).map(([key]) => key)
216
- });
217
- if (isCancel(enabledChecks)) {
218
- cancel("Configuration cancelled");
219
- return;
220
- }
221
- const enabledSeverity = await multiselect({
222
- message: "Select severity levels for enabled checks:",
223
- options: [
224
- {
225
- value: "suggestion",
226
- label: "Suggestion"
227
- },
228
- {
229
- value: "warning",
230
- label: "Warning"
231
- },
232
- {
233
- value: "critical",
234
- label: "Critical"
235
- }
236
- ],
237
- initialValues: Object.entries(currentConfig.severityLevels).filter(([_, enabled]) => enabled).map(([key]) => key)
238
- });
239
- if (isCancel(enabledSeverity)) {
240
- cancel("Configuration cancelled");
241
- return;
242
- }
243
- const contextLevel = await select({
244
- message: "Select context level for analysis:",
245
- options: [{
246
- value: "minimal",
247
- label: "Minimal (Just Actual Changes)"
248
- }, {
249
- value: "normal",
250
- label: "Normal (Actual Changes + Context Lines)"
251
- }],
252
- initialValue: currentConfig.context
253
- });
254
- if (isCancel(contextLevel)) {
255
- cancel("Configuration cancelled");
256
- return;
257
- }
258
- let customRule = currentConfig.customRule;
259
- if (currentConfig.customRule) {
260
- log.info(`Current custom rule: ${currentConfig.customRule}`);
261
- const editCustomRule = await confirm({
262
- message: "Would you like to edit the custom rule? (Currently only available to pro users)",
263
- initialValue: false
264
- });
265
- if (isCancel(editCustomRule)) {
266
- cancel("Configuration cancelled");
267
- return;
268
- }
269
- if (editCustomRule) {
270
- const newCustomRule = await text({
271
- message: "Enter new custom rule (leave empty to remove):",
272
- initialValue: currentConfig.customRule,
273
- validate: (value) => {
274
- const val = String(value).trim();
275
- if (!val) return void 0;
276
- if (val.length > MAX_CUSTOM_PROMPT_LENGTH) return `Custom rule must be ${MAX_CUSTOM_PROMPT_LENGTH} characters or less (current: ${val.length})`;
277
- }
278
- });
279
- if (isCancel(newCustomRule)) {
280
- cancel("Configuration cancelled");
281
- return;
282
- }
283
- customRule = String(newCustomRule).trim();
284
- }
285
- } else {
286
- const addCustomRule = await confirm({
287
- message: "Would you like to add a custom rule for this project? (Currently only available to pro users)",
288
- initialValue: false
289
- });
290
- if (isCancel(addCustomRule)) {
291
- cancel("Configuration cancelled");
292
- return;
293
- }
294
- if (addCustomRule) {
295
- const newCustomRule = await text({
296
- message: "Enter custom rule (leave empty to skip):",
297
- placeholder: "e.g., Check for proper error handling in async functions",
298
- validate: (value) => {
299
- const val = String(value).trim();
300
- if (!val) return void 0;
301
- if (val.length > MAX_CUSTOM_PROMPT_LENGTH) return `Custom rule must be ${MAX_CUSTOM_PROMPT_LENGTH} characters or less (current: ${val.length})`;
302
- }
303
- });
304
- if (isCancel(newCustomRule)) {
305
- cancel("Configuration cancelled");
306
- return;
307
- }
308
- customRule = String(newCustomRule).trim();
309
- }
310
- }
311
- const newConfig = {
312
- context: contextLevel,
313
- checks: {
314
- security: enabledChecks.includes("security"),
315
- performance: enabledChecks.includes("performance"),
316
- codeQuality: enabledChecks.includes("codeQuality"),
317
- architecture: enabledChecks.includes("architecture")
318
- },
319
- severityLevels: {
320
- suggestion: enabledSeverity.includes("suggestion"),
321
- warning: enabledSeverity.includes("warning"),
322
- critical: enabledSeverity.includes("critical")
323
- },
324
- customRule
325
- };
326
- if (JSON.stringify(newConfig) === JSON.stringify(currentConfig)) {
327
- outro("No changes made to the configuration.");
328
- return;
329
- }
330
- const confirmUpdate = await confirm({ message: "Save this configuration?" });
331
- if (isCancel(confirmUpdate)) {
332
- cancel("Configuration cancelled");
333
- return;
334
- }
335
- if (!confirmUpdate) {
336
- outro("Configuration not saved.");
337
- return;
338
- }
339
- const projects = loadProjectsConfig();
340
- projects[projectId] = newConfig;
341
- saveProjectsConfig(projects);
342
- outro("✓ Configuration updated for this project!");
343
- }
71
+ }
72
+ };
344
73
 
345
74
  //#endregion
346
75
  //#region src/data/ignore.json
@@ -465,16 +194,49 @@ var ignore = [
465
194
  "*.rdb"
466
195
  ];
467
196
 
197
+ //#endregion
198
+ //#region src/utils/global.ts
199
+ function createDiffHash(diff) {
200
+ return createHash("md5").update(diff).digest("base64url");
201
+ }
202
+ function addGitLineNumbers(diff) {
203
+ if (!diff.trim()) return diff;
204
+ const lines = diff.split("\n");
205
+ const result = [];
206
+ let oldLine = 0;
207
+ let newLine = 0;
208
+ for (const line of lines) if (line.startsWith("@@")) {
209
+ const match = line.match(/@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
210
+ if (match) {
211
+ oldLine = Number.parseInt(match[1], 10);
212
+ newLine = Number.parseInt(match[2], 10);
213
+ }
214
+ result.push(line);
215
+ } else if (line.startsWith("---") || line.startsWith("+++") || line.startsWith("diff ") || line.startsWith("index ")) result.push(line);
216
+ else if (line.startsWith("-")) {
217
+ result.push(`${oldLine}:${line}`);
218
+ oldLine++;
219
+ } else if (line.startsWith("+")) {
220
+ result.push(`${newLine}:${line}`);
221
+ newLine++;
222
+ } else {
223
+ result.push(`${newLine}:${line}`);
224
+ oldLine++;
225
+ newLine++;
226
+ }
227
+ return result.join("\n");
228
+ }
229
+ const MESSAGES = { noGit: "No .git folder found. Run this inside a git repository." };
230
+
468
231
  //#endregion
469
232
  //#region src/utils/git.ts
470
- function getStagedDiff(context) {
471
- const gitContextCommand = context === "minimal" ? [] : ["--function-context"];
233
+ function getStagedDiff() {
472
234
  try {
473
235
  return addGitLineNumbers(execFileSync("git", [
474
236
  "diff",
475
237
  "--cached",
476
238
  "--no-color",
477
- ...gitContextCommand,
239
+ "--function-context",
478
240
  "--diff-algorithm=histogram",
479
241
  "--diff-filter=AMC",
480
242
  "--",
@@ -493,15 +255,14 @@ function getStagedDiff(context) {
493
255
  return "";
494
256
  }
495
257
  }
496
- function getLastDiff(context) {
497
- const gitContextCommand = context === "minimal" ? [] : ["--function-context"];
258
+ function getLastDiff() {
498
259
  try {
499
260
  return execFileSync("git", [
500
261
  "diff",
501
262
  "HEAD~1",
502
263
  "HEAD",
503
264
  "--no-color",
504
- ...gitContextCommand,
265
+ "--function-context",
505
266
  "--diff-algorithm=histogram",
506
267
  "--diff-filter=AMC",
507
268
  "--",
@@ -613,6 +374,7 @@ async function sendToCommitGuard(diff, eslint, config$1) {
613
374
  const errorText = await response.text();
614
375
  let errorMessage = "Failed to analyze commit";
615
376
  if (response.status === 401) errorMessage = "Invalid API key. Check your key with \"commitguard keys\" or get a new one at https://commitguard.ai";
377
+ else if (response.status === 402) errorMessage = "You’ve reached your plan limit. Upgrade now with 20% off using code SAVE20 at checkout: https://commitguard.ai/dashboard";
616
378
  else if (response.status === 429) errorMessage = "Rate limit exceeded. Please try again later";
617
379
  else if (response.status === 500) errorMessage = "CommitGuard service error. Please try again later";
618
380
  else if (response.status >= 400 && response.status < 500) errorMessage = `Request error: ${errorText || "Invalid request"}`;
@@ -630,7 +392,7 @@ async function bypassCommitGuard() {
630
392
  const apiKey = process.env.COMMITGUARD_API_KEY || getGlobalKey() || null;
631
393
  if (!apiKey) throw new Error("No API key found. Set one globally with \"commitguard keys\" or add COMMITGUARD_API_KEY to your .env file. Get your free API key at https://commitguard.ai");
632
394
  const apiUrl = process.env.COMMITGUARD_API_BYPASS_URL || "https://api.commitguard.ai/v1/bypass";
633
- const diff = getLastDiff(loadConfig().context);
395
+ const diff = getLastDiff();
634
396
  const controller = new AbortController();
635
397
  const timeoutId = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT);
636
398
  try {
@@ -657,6 +419,226 @@ async function bypassCommitGuard() {
657
419
  }
658
420
  }
659
421
 
422
+ //#endregion
423
+ //#region src/utils/config.ts
424
+ const MAX_CUSTOM_PROMPT_LENGTH = 500;
425
+ const CONFIG_DIR = join(homedir(), ".commitguard");
426
+ const PROJECTS_CONFIG_PATH = join(CONFIG_DIR, "projects.json");
427
+ let projectsConfigCache = null;
428
+ const GIT_DIR$1 = ".git";
429
+ function ensureConfigDir() {
430
+ if (!existsSync(CONFIG_DIR)) try {
431
+ mkdirSync(CONFIG_DIR, { recursive: true });
432
+ } catch (e) {
433
+ consola.error(`Failed to create config directory at ${CONFIG_DIR}: ${e.message}`);
434
+ }
435
+ }
436
+ function getDefaultConfig() {
437
+ return {
438
+ checks: {
439
+ security: true,
440
+ performance: true,
441
+ codeQuality: true,
442
+ architecture: true
443
+ },
444
+ severityLevels: {
445
+ critical: true,
446
+ warning: true,
447
+ suggestion: false
448
+ },
449
+ customRule: ""
450
+ };
451
+ }
452
+ let projectIdCache = null;
453
+ function getProjectId() {
454
+ if (projectIdCache) return projectIdCache;
455
+ try {
456
+ projectIdCache = execFileSync("git", [
457
+ "rev-list",
458
+ "--max-parents=0",
459
+ "HEAD"
460
+ ], {
461
+ encoding: "utf8",
462
+ stdio: [
463
+ "pipe",
464
+ "pipe",
465
+ "ignore"
466
+ ]
467
+ }).trim().split("\n")[0];
468
+ return projectIdCache;
469
+ } catch {
470
+ consola.error("Warning: Unable to determine project ID. Using current working directory as fallback project ID.");
471
+ projectIdCache = process.cwd();
472
+ return projectIdCache;
473
+ }
474
+ }
475
+ function loadProjectsConfig() {
476
+ if (projectsConfigCache) return projectsConfigCache;
477
+ if (existsSync(PROJECTS_CONFIG_PATH)) try {
478
+ const content = readFileSync(PROJECTS_CONFIG_PATH, "utf8");
479
+ projectsConfigCache = JSON.parse(content);
480
+ return projectsConfigCache;
481
+ } catch {
482
+ consola.warn("Failed to parse projects config");
483
+ }
484
+ projectsConfigCache = {};
485
+ return projectsConfigCache;
486
+ }
487
+ function saveProjectsConfig(projects) {
488
+ try {
489
+ ensureConfigDir();
490
+ writeFileSync(PROJECTS_CONFIG_PATH, JSON.stringify(projects, null, 2));
491
+ projectsConfigCache = projects;
492
+ } catch (e) {
493
+ consola.error(`Failed to save projects config: ${e.message}`);
494
+ }
495
+ }
496
+ function loadConfig() {
497
+ const projectId = getProjectId();
498
+ return loadProjectsConfig()[projectId] || getDefaultConfig();
499
+ }
500
+ async function manageConfig() {
501
+ if (!existsSync(GIT_DIR$1)) {
502
+ cancel(MESSAGES.noGit);
503
+ return;
504
+ }
505
+ const projectId = getProjectId();
506
+ const currentConfig = loadConfig();
507
+ intro(`CommitGuard Configuration`);
508
+ const enabledChecks = await multiselect({
509
+ message: "Select enabled checks for this project:",
510
+ options: [
511
+ {
512
+ value: "security",
513
+ label: "Security"
514
+ },
515
+ {
516
+ value: "performance",
517
+ label: "Performance"
518
+ },
519
+ {
520
+ value: "codeQuality",
521
+ label: "Code Quality"
522
+ },
523
+ {
524
+ value: "architecture",
525
+ label: "Architecture"
526
+ }
527
+ ],
528
+ initialValues: Object.entries(currentConfig.checks).filter(([_, enabled]) => enabled).map(([key]) => key)
529
+ });
530
+ if (isCancel(enabledChecks)) {
531
+ cancel("Configuration cancelled");
532
+ return;
533
+ }
534
+ const enabledSeverity = await multiselect({
535
+ message: "Select severity levels for enabled checks:",
536
+ options: [
537
+ {
538
+ value: "suggestion",
539
+ label: "Suggestion"
540
+ },
541
+ {
542
+ value: "warning",
543
+ label: "Warning"
544
+ },
545
+ {
546
+ value: "critical",
547
+ label: "Critical"
548
+ }
549
+ ],
550
+ initialValues: Object.entries(currentConfig.severityLevels).filter(([_, enabled]) => enabled).map(([key]) => key)
551
+ });
552
+ if (isCancel(enabledSeverity)) {
553
+ cancel("Configuration cancelled");
554
+ return;
555
+ }
556
+ let customRule = currentConfig.customRule;
557
+ if (currentConfig.customRule) {
558
+ log.info(`Current custom rule: ${currentConfig.customRule}`);
559
+ const editCustomRule = await confirm({
560
+ message: "Would you like to edit the custom rule? (Currently only available to pro users)",
561
+ initialValue: false
562
+ });
563
+ if (isCancel(editCustomRule)) {
564
+ cancel("Configuration cancelled");
565
+ return;
566
+ }
567
+ if (editCustomRule) {
568
+ const newCustomRule = await text({
569
+ message: "Enter new custom rule (leave empty to remove):",
570
+ initialValue: currentConfig.customRule,
571
+ validate: (value) => {
572
+ const val = String(value).trim();
573
+ if (!val) return void 0;
574
+ if (val.length > MAX_CUSTOM_PROMPT_LENGTH) return `Custom rule must be ${MAX_CUSTOM_PROMPT_LENGTH} characters or less (current: ${val.length})`;
575
+ }
576
+ });
577
+ if (isCancel(newCustomRule)) {
578
+ cancel("Configuration cancelled");
579
+ return;
580
+ }
581
+ customRule = String(newCustomRule).trim();
582
+ }
583
+ } else {
584
+ const addCustomRule = await confirm({
585
+ message: "Would you like to add a custom rule for this project? (Currently only available to pro users)",
586
+ initialValue: false
587
+ });
588
+ if (isCancel(addCustomRule)) {
589
+ cancel("Configuration cancelled");
590
+ return;
591
+ }
592
+ if (addCustomRule) {
593
+ const newCustomRule = await text({
594
+ message: "Enter custom rule (leave empty to skip):",
595
+ placeholder: "e.g., Check for proper error handling in async functions",
596
+ validate: (value) => {
597
+ const val = String(value).trim();
598
+ if (!val) return void 0;
599
+ if (val.length > MAX_CUSTOM_PROMPT_LENGTH) return `Custom rule must be ${MAX_CUSTOM_PROMPT_LENGTH} characters or less (current: ${val.length})`;
600
+ }
601
+ });
602
+ if (isCancel(newCustomRule)) {
603
+ cancel("Configuration cancelled");
604
+ return;
605
+ }
606
+ customRule = String(newCustomRule).trim();
607
+ }
608
+ }
609
+ const newConfig = {
610
+ checks: {
611
+ security: enabledChecks.includes("security"),
612
+ performance: enabledChecks.includes("performance"),
613
+ codeQuality: enabledChecks.includes("codeQuality"),
614
+ architecture: enabledChecks.includes("architecture")
615
+ },
616
+ severityLevels: {
617
+ suggestion: enabledSeverity.includes("suggestion"),
618
+ warning: enabledSeverity.includes("warning"),
619
+ critical: enabledSeverity.includes("critical")
620
+ },
621
+ customRule
622
+ };
623
+ if (JSON.stringify(newConfig) === JSON.stringify(currentConfig)) {
624
+ outro("No changes made to the configuration.");
625
+ return;
626
+ }
627
+ const confirmUpdate = await confirm({ message: "Save this configuration?" });
628
+ if (isCancel(confirmUpdate)) {
629
+ cancel("Configuration cancelled");
630
+ return;
631
+ }
632
+ if (!confirmUpdate) {
633
+ outro("Configuration not saved.");
634
+ return;
635
+ }
636
+ const projects = loadProjectsConfig();
637
+ projects[projectId] = newConfig;
638
+ saveProjectsConfig(projects);
639
+ outro("✓ Configuration updated for this project!");
640
+ }
641
+
660
642
  //#endregion
661
643
  //#region src/utils/eslint.ts
662
644
  const cacheDir = join(homedir(), ".cache", "commitguard");
@@ -944,7 +926,7 @@ function groupIssuesByFile(issues = []) {
944
926
  };
945
927
  }
946
928
  async function onStaged() {
947
- const diff = getStagedDiff(config.context);
929
+ const diff = getStagedDiff();
948
930
  if (!diff.trim()) {
949
931
  clearCache();
950
932
  return;
@@ -965,7 +947,7 @@ async function onStaged() {
965
947
  }
966
948
  }
967
949
  function getCachedAnalysis(diff, diffHash) {
968
- const effectiveDiff = diff ?? getStagedDiff(config.context);
950
+ const effectiveDiff = diff ?? getStagedDiff();
969
951
  if (!effectiveDiff.trim()) return {
970
952
  analysis: {
971
953
  status: "pass",
@@ -984,7 +966,7 @@ function getCachedAnalysis(diff, diffHash) {
984
966
  };
985
967
  }
986
968
  async function validateCommit() {
987
- const diff = getStagedDiff(config.context);
969
+ const diff = getStagedDiff();
988
970
  const diffHash = diff.trim() ? createDiffHash(diff) : "";
989
971
  const cached = getCachedAnalysis(diff, diffHash);
990
972
  if (!cached) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@commitguard/cli",
3
3
  "type": "module",
4
- "version": "0.0.14",
4
+ "version": "0.0.16",
5
5
  "description": "AI-powered git commit checker that blocks bad code before it ships",
6
6
  "license": "MIT",
7
7
  "repository": {