New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@commitguard/cli

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@commitguard/cli - npm Package Compare versions

Comparing version
0.0.13
to
0.0.14
+167
README.md
# CommitGuard
Protect your codebase with every commit. CommitGuard automatically analyzes your code for security vulnerabilities, performance issues, and code quality problems before they enter your repository. Grab your free API key at https://commitguard.ai.
## Installation
Get CommitGuard running in under 60 seconds. It works seamlessly with any git repository and integrates automatically with VSCode and other git clients.
### Quick Start
**1. Install CommitGuard globally**
```bash
npm install -g @commitguard/cli
```
**2. Navigate to your project**
```bash
cd your-project
```
**3. Initialize CommitGuard**
```bash
commitguard init
```
**4. Commit as usual**
CommitGuard now runs automatically on every commit. It works with all git integrations including VSCode, terminal, and other git clients.
```bash
git commit -m "Add new feature"
[CommitGuard] Analyzing commit...
✓ Commit passed all checks
```
## Usage
### Bypassing Checks
To bypass CommitGuard checks for a specific commit, add `--skip` to your commit message:
```bash
git commit -m "Add new feature --skip"
```
The `--skip` flag is automatically removed from the final commit message. When using git in your terminal, you'll be prompted to confirm if you want to bypass checks.
### Configuring Checks
View or update CommitGuard preferences for your repository:
```bash
commitguard config
```
On the Pro plan, you can add custom rules through the config comand.
## CLI Commands
### `commitguard init`
Install CommitGuard in your current repository.
```bash
$ commitguard init
✓ CommitGuard installed successfully
```
### `commitguard remove`
Remove CommitGuard from the current repository.
```bash
$ commitguard remove
✓ CommitGuard removed
```
### `commitguard config`
View or update CommitGuard preferences for the current repository. Pro plan users can add custom rules.
```bash
$ commitguard config
Select enabled checks for this project:
Security, Performance, Code Quality, Architecture
```
### `commitguard keys`
Manage your global API key for CommitGuard.
```bash
$ commitguard keys
Current API key: sk-ant-***************
```
## What Happens After Installation?
- Every commit is analyzed before it's created.
- No config files are added to your project
- Bypass checks anytime with `--skip` in your commit message
- Works seamlessly with all git clients and IDEs
## Troubleshooting
<details>
<summary><strong>CommitGuard isn't running on commits</strong></summary>
Try reinstalling the hooks:
```bash
commitguard remove
commitguard init
```
Verify that the hooks are installed:
```bash
ls -la .git/hooks/
```
You should see a `pre-commit` hook file.
</details>
<details>
<summary><strong>How do I skip a single commit?</strong></summary>
Add `--skip` to your commit message:
```bash
git commit -m "Emergency fix --skip"
```
The `--skip` flag is automatically removed from the final message.
</details>
<details>
<summary><strong>How do I completely remove CommitGuard?</strong></summary>
Remove the hooks and uninstall the package:
```bash
commitguard remove
npm uninstall -g @commitguard/cli
```
</details>
## Features
- **Security Analysis** - Detect vulnerabilities before they reach your repo
- **Performance Checks** - Identify performance bottlenecks early
- **Code Quality** - Maintain consistent code standards
- **Architecture Review** - Ensure architectural patterns are followed
- **Zero Configuration** - Works out of the box
- **Universal Compatibility** - Works with any git workflow
-- **Custom Rules** - Add your own custom checks to the code reviews
## Support
For issues, feature requests, or questions related to this package please open an issue or email us at hello@commitguard.ai
## License
MIT
+343
-303

@@ -6,8 +6,8 @@ #!/usr/bin/env node

import { execFileSync, execSync } from "node:child_process";
import { createHash } from "node:crypto";
import { cancel, confirm, intro, isCancel, log, multiselect, note, outro, text } from "@clack/prompts";
import { Entry } from "@napi-rs/keyring";
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
import { homedir } from "node:os";
import { dirname, join } from "node:path";
import { cancel, confirm, intro, isCancel, log, multiselect, note, outro, select, text } from "@clack/prompts";
import { createHash } from "node:crypto";
import { Entry } from "@napi-rs/keyring";
import { fileURLToPath, pathToFileURL } from "node:url";

@@ -21,3 +21,3 @@ import { readFile } from "node:fs/promises";

//#region package.json
var version = "0.0.13";
var version = "0.0.14";
var package_default = {

@@ -77,2 +77,273 @@ name: "@commitguard/cli",

//#endregion
//#region src/utils/global.ts
function createDiffHash(diff) {
return createHash("md5").update(diff).digest("base64url");
}
function addGitLineNumbers(diff) {
if (!diff.trim()) return diff;
const lines = diff.split("\n");
const result = [];
let oldLine = 0;
let newLine = 0;
for (const line of lines) if (line.startsWith("@@")) {
const match = line.match(/@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
if (match) {
oldLine = Number.parseInt(match[1], 10);
newLine = Number.parseInt(match[2], 10);
}
result.push(line);
} else if (line.startsWith("---") || line.startsWith("+++") || line.startsWith("diff ") || line.startsWith("index ")) result.push(line);
else if (line.startsWith("-")) {
result.push(`${oldLine}:${line}`);
oldLine++;
} else if (line.startsWith("+")) {
result.push(`${newLine}:${line}`);
newLine++;
} else {
result.push(`${newLine}:${line}`);
oldLine++;
newLine++;
}
return result.join("\n");
}
const MESSAGES = { noGit: "No .git folder found. Run this inside a git repository." };
//#endregion
//#region src/utils/config.ts
const MAX_CUSTOM_PROMPT_LENGTH = 500;
const CONFIG_DIR = join(homedir(), ".commitguard");
const PROJECTS_CONFIG_PATH = join(CONFIG_DIR, "projects.json");
let projectsConfigCache = null;
const GIT_DIR$1 = ".git";
function ensureConfigDir() {
if (!existsSync(CONFIG_DIR)) try {
mkdirSync(CONFIG_DIR, { recursive: true });
} catch (e) {
consola.error(`Failed to create config directory at ${CONFIG_DIR}: ${e.message}`);
}
}
function getDefaultConfig() {
return {
context: "normal",
checks: {
security: true,
performance: true,
codeQuality: true,
architecture: true
},
severityLevels: {
critical: true,
warning: true,
suggestion: false
},
customRule: ""
};
}
let projectIdCache = null;
function getProjectId() {
if (projectIdCache) return projectIdCache;
try {
projectIdCache = execFileSync("git", [
"rev-list",
"--max-parents=0",
"HEAD"
], {
encoding: "utf8",
stdio: [
"pipe",
"pipe",
"ignore"
]
}).trim().split("\n")[0];
return projectIdCache;
} catch {
consola.error("Warning: Unable to determine project ID. Using current working directory as fallback project ID.");
projectIdCache = process.cwd();
return projectIdCache;
}
}
function loadProjectsConfig() {
if (projectsConfigCache) return projectsConfigCache;
if (existsSync(PROJECTS_CONFIG_PATH)) try {
const content = readFileSync(PROJECTS_CONFIG_PATH, "utf8");
projectsConfigCache = JSON.parse(content);
return projectsConfigCache;
} catch {
consola.warn("Failed to parse projects config");
}
projectsConfigCache = {};
return projectsConfigCache;
}
function saveProjectsConfig(projects) {
try {
ensureConfigDir();
writeFileSync(PROJECTS_CONFIG_PATH, JSON.stringify(projects, null, 2));
projectsConfigCache = projects;
} catch (e) {
consola.error(`Failed to save projects config: ${e.message}`);
}
}
function loadConfig() {
const projectId = getProjectId();
return loadProjectsConfig()[projectId] || getDefaultConfig();
}
async function manageConfig() {
if (!existsSync(GIT_DIR$1)) {
cancel(MESSAGES.noGit);
return;
}
const projectId = getProjectId();
const currentConfig = loadConfig();
intro(`CommitGuard Configuration`);
const enabledChecks = await multiselect({
message: "Select enabled checks for this project:",
options: [
{
value: "security",
label: "Security"
},
{
value: "performance",
label: "Performance"
},
{
value: "codeQuality",
label: "Code Quality"
},
{
value: "architecture",
label: "Architecture"
}
],
initialValues: Object.entries(currentConfig.checks).filter(([_, enabled]) => enabled).map(([key]) => key)
});
if (isCancel(enabledChecks)) {
cancel("Configuration cancelled");
return;
}
const enabledSeverity = await multiselect({
message: "Select severity levels for enabled checks:",
options: [
{
value: "suggestion",
label: "Suggestion"
},
{
value: "warning",
label: "Warning"
},
{
value: "critical",
label: "Critical"
}
],
initialValues: Object.entries(currentConfig.severityLevels).filter(([_, enabled]) => enabled).map(([key]) => key)
});
if (isCancel(enabledSeverity)) {
cancel("Configuration cancelled");
return;
}
const contextLevel = await select({
message: "Select context level for analysis:",
options: [{
value: "minimal",
label: "Minimal (Just Actual Changes)"
}, {
value: "normal",
label: "Normal (Actual Changes + Context Lines)"
}],
initialValue: currentConfig.context
});
if (isCancel(contextLevel)) {
cancel("Configuration cancelled");
return;
}
let customRule = currentConfig.customRule;
if (currentConfig.customRule) {
log.info(`Current custom rule: ${currentConfig.customRule}`);
const editCustomRule = await confirm({
message: "Would you like to edit the custom rule? (Currently only available to pro users)",
initialValue: false
});
if (isCancel(editCustomRule)) {
cancel("Configuration cancelled");
return;
}
if (editCustomRule) {
const newCustomRule = await text({
message: "Enter new custom rule (leave empty to remove):",
initialValue: currentConfig.customRule,
validate: (value) => {
const val = String(value).trim();
if (!val) return void 0;
if (val.length > MAX_CUSTOM_PROMPT_LENGTH) return `Custom rule must be ${MAX_CUSTOM_PROMPT_LENGTH} characters or less (current: ${val.length})`;
}
});
if (isCancel(newCustomRule)) {
cancel("Configuration cancelled");
return;
}
customRule = String(newCustomRule).trim();
}
} else {
const addCustomRule = await confirm({
message: "Would you like to add a custom rule for this project? (Currently only available to pro users)",
initialValue: false
});
if (isCancel(addCustomRule)) {
cancel("Configuration cancelled");
return;
}
if (addCustomRule) {
const newCustomRule = await text({
message: "Enter custom rule (leave empty to skip):",
placeholder: "e.g., Check for proper error handling in async functions",
validate: (value) => {
const val = String(value).trim();
if (!val) return void 0;
if (val.length > MAX_CUSTOM_PROMPT_LENGTH) return `Custom rule must be ${MAX_CUSTOM_PROMPT_LENGTH} characters or less (current: ${val.length})`;
}
});
if (isCancel(newCustomRule)) {
cancel("Configuration cancelled");
return;
}
customRule = String(newCustomRule).trim();
}
}
const newConfig = {
context: contextLevel,
checks: {
security: enabledChecks.includes("security"),
performance: enabledChecks.includes("performance"),
codeQuality: enabledChecks.includes("codeQuality"),
architecture: enabledChecks.includes("architecture")
},
severityLevels: {
suggestion: enabledSeverity.includes("suggestion"),
warning: enabledSeverity.includes("warning"),
critical: enabledSeverity.includes("critical")
},
customRule
};
if (JSON.stringify(newConfig) === JSON.stringify(currentConfig)) {
outro("No changes made to the configuration.");
return;
}
const confirmUpdate = await confirm({ message: "Save this configuration?" });
if (isCancel(confirmUpdate)) {
cancel("Configuration cancelled");
return;
}
if (!confirmUpdate) {
outro("Configuration not saved.");
return;
}
const projects = loadProjectsConfig();
projects[projectId] = newConfig;
saveProjectsConfig(projects);
outro("✓ Configuration updated for this project!");
}
//#endregion
//#region src/data/ignore.json

@@ -201,38 +472,5 @@ var ignore = [

//#endregion
//#region src/utils/global.ts
function createDiffHash(diff) {
return createHash("md5").update(diff).digest("base64url");
}
function addGitLineNumbers(diff) {
if (!diff.trim()) return diff;
const lines = diff.split("\n");
const result = [];
let oldLine = 0;
let newLine = 0;
for (const line of lines) if (line.startsWith("@@")) {
const match = line.match(/@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
if (match) {
oldLine = Number.parseInt(match[1], 10);
newLine = Number.parseInt(match[2], 10);
}
result.push(line);
} else if (line.startsWith("---") || line.startsWith("+++") || line.startsWith("diff ") || line.startsWith("index ")) result.push(line);
else if (line.startsWith("-")) {
result.push(`${oldLine}:${line}`);
oldLine++;
} else if (line.startsWith("+")) {
result.push(`${newLine}:${line}`);
newLine++;
} else {
result.push(`${newLine}:${line}`);
oldLine++;
newLine++;
}
return result.join("\n");
}
const MESSAGES = { noGit: "No .git folder found. Run this inside a git repository." };
//#endregion
//#region src/utils/git.ts
function getStagedDiff() {
function getStagedDiff(context) {
const gitContextCommand = context === "minimal" ? [] : ["--function-context"];
try {

@@ -243,3 +481,3 @@ return addGitLineNumbers(execFileSync("git", [

"--no-color",
"--function-context",
...gitContextCommand,
"--diff-algorithm=histogram",

@@ -263,3 +501,4 @@ "--diff-filter=AMC",

}
function getLastDiff() {
function getLastDiff(context) {
const gitContextCommand = context === "minimal" ? [] : ["--function-context"];
try {

@@ -271,3 +510,3 @@ return execFileSync("git", [

"--no-color",
"--function-context",
...gitContextCommand,
"--diff-algorithm=histogram",

@@ -357,30 +596,41 @@ "--diff-filter=AMC",

//#region src/utils/api.ts
async function sendToCommitGuard(diff, eslint, config) {
const DEFAULT_TIMEOUT = 2e4;
async function sendToCommitGuard(diff, eslint, config$1) {
const apiKey = process.env.COMMITGUARD_API_KEY || getGlobalKey() || null;
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");
const apiUrl = process.env.COMMITGUARD_API_URL || "https://api.commitguard.ai/v1/analyze";
const response = await fetch(apiUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${apiKey}`,
"User-Agent": "commitguard-cli"
},
body: JSON.stringify({
diff,
eslint,
config
})
});
if (!response.ok) {
const errorText = await response.text();
let errorMessage = "Failed to analyze commit";
if (response.status === 401) errorMessage = "Invalid API key. Check your key with \"commitguard keys\" or get a new one at https://commitguard.ai";
else if (response.status === 429) errorMessage = "Rate limit exceeded. Please try again later";
else if (response.status === 500) errorMessage = "CommitGuard service error. Please try again later";
else if (response.status >= 400 && response.status < 500) errorMessage = `Request error: ${errorText || "Invalid request"}`;
else errorMessage = `Service unavailable (${response.status}). Please try again later`;
throw new Error(errorMessage);
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT);
try {
const response = await fetch(apiUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${apiKey}`,
"User-Agent": "commitguard-cli"
},
body: JSON.stringify({
diff,
eslint,
config: config$1
}),
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
const errorText = await response.text();
let errorMessage = "Failed to analyze commit";
if (response.status === 401) errorMessage = "Invalid API key. Check your key with \"commitguard keys\" or get a new one at https://commitguard.ai";
else if (response.status === 429) errorMessage = "Rate limit exceeded. Please try again later";
else if (response.status === 500) errorMessage = "CommitGuard service error. Please try again later";
else if (response.status >= 400 && response.status < 500) errorMessage = `Request error: ${errorText || "Invalid request"}`;
else errorMessage = `Service unavailable (${response.status}). Please try again later`;
throw new Error(errorMessage);
}
return await response.json();
} catch (error) {
clearTimeout(timeoutId);
if (error instanceof Error && error.name === "AbortError") throw new Error(`Request timed out after ${DEFAULT_TIMEOUT}ms`);
throw error;
}
return await response.json();
}

@@ -391,237 +641,27 @@ async function bypassCommitGuard() {

const apiUrl = process.env.COMMITGUARD_API_BYPASS_URL || "https://api.commitguard.ai/v1/bypass";
const diff = getLastDiff();
const response = await fetch(apiUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${apiKey}`,
"User-Agent": "commitguard-cli"
},
body: JSON.stringify({ diff })
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`API request failed (${response.status}): ${errorText}`);
}
return await response.json();
}
//#endregion
//#region src/utils/config.ts
const MAX_CUSTOM_PROMPT_LENGTH = 500;
const CONFIG_DIR = join(homedir(), ".commitguard");
const PROJECTS_CONFIG_PATH = join(CONFIG_DIR, "projects.json");
let projectsConfigCache = null;
const GIT_DIR$1 = ".git";
function ensureConfigDir() {
if (!existsSync(CONFIG_DIR)) try {
mkdirSync(CONFIG_DIR, { recursive: true });
} catch (e) {
consola.error(`Failed to create config directory at ${CONFIG_DIR}: ${e.message}`);
}
}
function getDefaultConfig() {
return {
checks: {
security: true,
performance: true,
codeQuality: true,
architecture: true
},
severityLevels: {
critical: true,
warning: true,
suggestion: false
},
customRule: ""
};
}
let projectIdCache = null;
function getProjectId() {
if (projectIdCache) return projectIdCache;
const diff = getLastDiff(loadConfig().context);
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT);
try {
projectIdCache = execFileSync("git", [
"rev-list",
"--max-parents=0",
"HEAD"
], {
encoding: "utf8",
stdio: [
"pipe",
"pipe",
"ignore"
]
}).trim().split("\n")[0];
return projectIdCache;
} catch {
consola.error("Warning: Unable to determine project ID. Using current working directory as fallback project ID.");
projectIdCache = process.cwd();
return projectIdCache;
}
}
function loadProjectsConfig() {
if (projectsConfigCache) return projectsConfigCache;
if (existsSync(PROJECTS_CONFIG_PATH)) try {
const content = readFileSync(PROJECTS_CONFIG_PATH, "utf8");
projectsConfigCache = JSON.parse(content);
return projectsConfigCache;
} catch {
consola.warn("Failed to parse projects config");
}
projectsConfigCache = {};
return projectsConfigCache;
}
function saveProjectsConfig(projects) {
try {
ensureConfigDir();
writeFileSync(PROJECTS_CONFIG_PATH, JSON.stringify(projects, null, 2));
projectsConfigCache = projects;
} catch (e) {
consola.error(`Failed to save projects config: ${e.message}`);
}
}
function loadConfig() {
const projectId = getProjectId();
return loadProjectsConfig()[projectId] || getDefaultConfig();
}
async function manageConfig() {
if (!existsSync(GIT_DIR$1)) {
cancel(MESSAGES.noGit);
return;
}
const projectId = getProjectId();
const currentConfig = loadConfig();
intro(`CommitGuard Configuration`);
const enabledChecks = await multiselect({
message: "Select enabled checks for this project:",
options: [
{
value: "security",
label: "Security"
const response = await fetch(apiUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${apiKey}`,
"User-Agent": "commitguard-cli"
},
{
value: "performance",
label: "Performance"
},
{
value: "codeQuality",
label: "Code Quality"
},
{
value: "architecture",
label: "Architecture"
}
],
initialValues: Object.entries(currentConfig.checks).filter(([_, enabled]) => enabled).map(([key]) => key)
});
if (isCancel(enabledChecks)) {
cancel("Configuration cancelled");
return;
}
const enabledSeverity = await multiselect({
message: "Select severity levels for enabled checks:",
options: [
{
value: "suggestion",
label: "Suggestion"
},
{
value: "warning",
label: "Warning"
},
{
value: "critical",
label: "Critical"
}
],
initialValues: Object.entries(currentConfig.severityLevels).filter(([_, enabled]) => enabled).map(([key]) => key)
});
if (isCancel(enabledSeverity)) {
cancel("Configuration cancelled");
return;
}
let customRule = currentConfig.customRule;
if (currentConfig.customRule) {
consola.info(`Current custom rule: ${currentConfig.customRule}`);
const editCustomRule = await confirm({
message: "Would you like to edit the custom rule? (Currently only available to pro users)",
initialValue: false
body: JSON.stringify({ diff }),
signal: controller.signal
});
if (isCancel(editCustomRule)) {
cancel("Configuration cancelled");
return;
clearTimeout(timeoutId);
if (!response.ok) {
const errorText = await response.text();
throw new Error(`API request failed (${response.status}): ${errorText}`);
}
if (editCustomRule) {
const newCustomRule = await text({
message: "Enter new custom rule (leave empty to remove):",
initialValue: currentConfig.customRule,
validate: (value) => {
const val = String(value).trim();
if (!val) return void 0;
if (val.length > MAX_CUSTOM_PROMPT_LENGTH) return `Custom rule must be ${MAX_CUSTOM_PROMPT_LENGTH} characters or less (current: ${val.length})`;
}
});
if (isCancel(newCustomRule)) {
cancel("Configuration cancelled");
return;
}
customRule = String(newCustomRule).trim();
}
} else {
const addCustomRule = await confirm({
message: "Would you like to add a custom rule for this project? (Currently only available to pro users)",
initialValue: false
});
if (isCancel(addCustomRule)) {
cancel("Configuration cancelled");
return;
}
if (addCustomRule) {
const newCustomRule = await text({
message: "Enter custom rule (leave empty to skip):",
placeholder: "e.g., Check for proper error handling in async functions",
validate: (value) => {
const val = String(value).trim();
if (!val) return void 0;
if (val.length > MAX_CUSTOM_PROMPT_LENGTH) return `Custom rule must be ${MAX_CUSTOM_PROMPT_LENGTH} characters or less (current: ${val.length})`;
}
});
if (isCancel(newCustomRule)) {
cancel("Configuration cancelled");
return;
}
customRule = String(newCustomRule).trim();
}
return await response.json();
} catch (error) {
clearTimeout(timeoutId);
if (error instanceof Error && error.name === "AbortError") throw new Error(`Request timed out after ${DEFAULT_TIMEOUT}ms`);
throw error;
}
const newConfig = {
checks: {
security: enabledChecks.includes("security"),
performance: enabledChecks.includes("performance"),
codeQuality: enabledChecks.includes("codeQuality"),
architecture: enabledChecks.includes("architecture")
},
severityLevels: {
suggestion: enabledSeverity.includes("suggestion"),
warning: enabledSeverity.includes("warning"),
critical: enabledSeverity.includes("critical")
},
customRule
};
if (JSON.stringify(newConfig) === JSON.stringify(currentConfig)) {
outro("No changes made to the configuration.");
return;
}
const confirmUpdate = await confirm({ message: "Save this configuration?" });
if (isCancel(confirmUpdate)) {
cancel("Configuration cancelled");
return;
}
if (!confirmUpdate) {
outro("Configuration not saved.");
return;
}
const projects = loadProjectsConfig();
projects[projectId] = newConfig;
saveProjectsConfig(projects);
outro("✓ Configuration updated for this project!");
}

@@ -688,9 +728,9 @@

});
const config = (await Promise.all(loaders)).find((r) => r !== null) ?? {
const config$1 = (await Promise.all(loaders)).find((r) => r !== null) ?? {
rules: {},
source: null
};
cache.setKey(cacheKey, config);
cache.setKey(cacheKey, config$1);
cache.save(true);
return config;
return config$1;
}

@@ -858,2 +898,3 @@

const CACHE_PATH = join(".git", "commitguard-cache.json");
const config = loadConfig();
const CATEGORY_LABELS = {

@@ -917,3 +958,3 @@ security: "🚨 [SECURITY]",

async function onStaged() {
const diff = getStagedDiff();
const diff = getStagedDiff(config.context);
if (!diff.trim()) {

@@ -927,3 +968,2 @@ clearCache();

try {
const config = loadConfig();
const response = await sendToCommitGuard(diff, (await getEslintRules()).rules, config);

@@ -941,3 +981,3 @@ writeCache({

function getCachedAnalysis(diff, diffHash) {
const effectiveDiff = diff ?? getStagedDiff();
const effectiveDiff = diff ?? getStagedDiff(config.context);
if (!effectiveDiff.trim()) return {

@@ -961,3 +1001,3 @@ analysis: {

async function validateCommit() {
const diff = getStagedDiff();
const diff = getStagedDiff(config.context);
const diffHash = diff.trim() ? createDiffHash(diff) : "";

@@ -964,0 +1004,0 @@ const cached = getCachedAnalysis(diff, diffHash);

{
"name": "@commitguard/cli",
"type": "module",
"version": "0.0.13",
"version": "0.0.14",
"description": "AI-powered git commit checker that blocks bad code before it ships",

@@ -6,0 +6,0 @@ "license": "MIT",