claude-git-hooks 2.1.0 → 2.3.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 (47) hide show
  1. package/CHANGELOG.md +178 -0
  2. package/README.md +203 -79
  3. package/bin/claude-hooks +295 -119
  4. package/lib/config.js +163 -0
  5. package/lib/hooks/pre-commit.js +179 -67
  6. package/lib/hooks/prepare-commit-msg.js +47 -41
  7. package/lib/utils/claude-client.js +93 -11
  8. package/lib/utils/file-operations.js +1 -65
  9. package/lib/utils/file-utils.js +65 -0
  10. package/lib/utils/package-info.js +75 -0
  11. package/lib/utils/preset-loader.js +209 -0
  12. package/lib/utils/prompt-builder.js +83 -67
  13. package/lib/utils/resolution-prompt.js +12 -2
  14. package/package.json +49 -50
  15. package/templates/ANALYZE_DIFF.md +33 -0
  16. package/templates/COMMIT_MESSAGE.md +24 -0
  17. package/templates/SUBAGENT_INSTRUCTION.md +1 -0
  18. package/templates/config.example.json +41 -0
  19. package/templates/presets/ai/ANALYSIS_PROMPT.md +133 -0
  20. package/templates/presets/ai/PRE_COMMIT_GUIDELINES.md +176 -0
  21. package/templates/presets/ai/config.json +12 -0
  22. package/templates/presets/ai/preset.json +42 -0
  23. package/templates/presets/backend/ANALYSIS_PROMPT.md +85 -0
  24. package/templates/presets/backend/PRE_COMMIT_GUIDELINES.md +87 -0
  25. package/templates/presets/backend/config.json +12 -0
  26. package/templates/presets/backend/preset.json +49 -0
  27. package/templates/presets/database/ANALYSIS_PROMPT.md +114 -0
  28. package/templates/presets/database/PRE_COMMIT_GUIDELINES.md +143 -0
  29. package/templates/presets/database/config.json +12 -0
  30. package/templates/presets/database/preset.json +38 -0
  31. package/templates/presets/default/config.json +12 -0
  32. package/templates/presets/default/preset.json +53 -0
  33. package/templates/presets/frontend/ANALYSIS_PROMPT.md +99 -0
  34. package/templates/presets/frontend/PRE_COMMIT_GUIDELINES.md +95 -0
  35. package/templates/presets/frontend/config.json +12 -0
  36. package/templates/presets/frontend/preset.json +50 -0
  37. package/templates/presets/fullstack/ANALYSIS_PROMPT.md +107 -0
  38. package/templates/presets/fullstack/CONSISTENCY_CHECKS.md +147 -0
  39. package/templates/presets/fullstack/PRE_COMMIT_GUIDELINES.md +125 -0
  40. package/templates/presets/fullstack/config.json +12 -0
  41. package/templates/presets/fullstack/preset.json +55 -0
  42. package/templates/shared/ANALYSIS_PROMPT.md +103 -0
  43. package/templates/shared/ANALYZE_DIFF.md +33 -0
  44. package/templates/shared/COMMIT_MESSAGE.md +24 -0
  45. package/templates/shared/PRE_COMMIT_GUIDELINES.md +145 -0
  46. package/templates/shared/RESOLUTION_PROMPT.md +32 -0
  47. package/templates/check-version.sh +0 -266
@@ -38,14 +38,22 @@ class PromptBuilderError extends Error {
38
38
  * Why absolute path: Ensures templates are found regardless of cwd (cross-platform)
39
39
  *
40
40
  * @param {string} templateName - Name of template file
41
- * @param {string} baseDir - Base directory (default: .claude)
41
+ * @param {string} baseDir - Base directory (default: try .claude, fallback to templates)
42
42
  * @returns {Promise<string>} Template content
43
43
  * @throws {PromptBuilderError} If template not found
44
44
  */
45
45
  const loadTemplate = async (templateName, baseDir = '.claude') => {
46
46
  // Why: Use repo root for absolute path (works on Windows/PowerShell/Git Bash)
47
47
  const repoRoot = getRepoRoot();
48
- const templatePath = path.join(repoRoot, baseDir, templateName);
48
+ let templatePath = path.join(repoRoot, baseDir, templateName);
49
+
50
+ // Try .claude first, fallback to templates/ if not found
51
+ try {
52
+ await fs.access(templatePath);
53
+ } catch {
54
+ // Try templates/ directory as fallback
55
+ templatePath = path.join(repoRoot, 'templates', templateName);
56
+ }
49
57
 
50
58
  logger.debug(
51
59
  'prompt-builder - loadTemplate',
@@ -104,6 +112,57 @@ const replaceTemplate = (template, variables) => {
104
112
  }, template);
105
113
  };
106
114
 
115
+ /**
116
+ * Loads a prompt template and replaces variables
117
+ * Why: High-level interface that combines loading and variable replacement
118
+ *
119
+ * @param {string} templateName - Name of template file
120
+ * @param {Object} variables - Variables to replace in template
121
+ * @param {string} baseDir - Base directory (default: .claude)
122
+ * @returns {Promise<string>} Prompt with replaced variables
123
+ * @throws {PromptBuilderError} If template not found
124
+ *
125
+ * Example:
126
+ * const prompt = await loadPrompt('COMMIT_MESSAGE.md', {
127
+ * FILE_LIST: 'file1.js\nfile2.js',
128
+ * FILE_COUNT: 2,
129
+ * INSERTIONS: 10,
130
+ * DELETIONS: 5
131
+ * });
132
+ */
133
+ const loadPrompt = async (templateName, variables = {}, baseDir = '.claude') => {
134
+ logger.debug(
135
+ 'prompt-builder - loadPrompt',
136
+ 'Loading prompt with variables',
137
+ { templateName, variableCount: Object.keys(variables).length }
138
+ );
139
+
140
+ try {
141
+ // Load template
142
+ const template = await loadTemplate(templateName, baseDir);
143
+
144
+ // Replace variables
145
+ const prompt = replaceTemplate(template, variables);
146
+
147
+ logger.debug(
148
+ 'prompt-builder - loadPrompt',
149
+ 'Prompt loaded successfully',
150
+ { templateName, promptLength: prompt.length }
151
+ );
152
+
153
+ return prompt;
154
+
155
+ } catch (error) {
156
+ logger.error(
157
+ 'prompt-builder - loadPrompt',
158
+ `Failed to load prompt: ${templateName}`,
159
+ error
160
+ );
161
+
162
+ throw error;
163
+ }
164
+ };
165
+
107
166
  /**
108
167
  * Formats file information for prompt
109
168
  * Why: Structures file data in readable format for Claude
@@ -144,6 +203,7 @@ const formatFileSection = ({ path, diff, content, isNew }) => {
144
203
  * @param {string} options.guidelinesName - Guidelines filename
145
204
  * @param {Array<Object>} options.files - Array of file data objects
146
205
  * @param {Object} options.metadata - Additional metadata (repo name, branch, etc.)
206
+ * @param {Object} options.subagentConfig - Subagent configuration (optional)
147
207
  * @returns {Promise<string>} Complete analysis prompt
148
208
  *
149
209
  * File data object structure:
@@ -158,12 +218,13 @@ const buildAnalysisPrompt = async ({
158
218
  templateName = 'CLAUDE_ANALYSIS_PROMPT_SONAR.md',
159
219
  guidelinesName = 'CLAUDE_PRE_COMMIT_SONAR.md',
160
220
  files = [],
161
- metadata = {}
221
+ metadata = {},
222
+ subagentConfig = null
162
223
  } = {}) => {
163
224
  logger.debug(
164
225
  'prompt-builder - buildAnalysisPrompt',
165
226
  'Building analysis prompt',
166
- { templateName, guidelinesName, fileCount: files.length }
227
+ { templateName, guidelinesName, fileCount: files.length, subagentsEnabled: subagentConfig?.enabled }
167
228
  );
168
229
 
169
230
  try {
@@ -176,6 +237,22 @@ const buildAnalysisPrompt = async ({
176
237
  // Start with template
177
238
  let prompt = template;
178
239
 
240
+ // Add subagent instruction if enabled and 3+ files
241
+ if (subagentConfig?.enabled && files.length >= 3) {
242
+ try {
243
+ const subagentInstruction = await loadTemplate('SUBAGENT_INSTRUCTION.md');
244
+ const subagentVariables = {
245
+ BATCH_SIZE: subagentConfig.batchSize || 3,
246
+ MODEL: subagentConfig.model || 'haiku'
247
+ };
248
+ prompt += '\n\n' + replaceTemplate(subagentInstruction, subagentVariables) + '\n';
249
+
250
+ logger.info(`🚀 Batch optimization enabled: ${files.length} files, ${subagentVariables.BATCH_SIZE} per batch, ${subagentVariables.MODEL} model`);
251
+ } catch (error) {
252
+ logger.warning('Subagent instruction template not found, proceeding without parallel analysis');
253
+ }
254
+ }
255
+
179
256
  // Add guidelines section
180
257
  prompt += '\n\n=== EVALUATION GUIDELINES ===\n';
181
258
  prompt += guidelines;
@@ -212,72 +289,11 @@ const buildAnalysisPrompt = async ({
212
289
  }
213
290
  };
214
291
 
215
- /**
216
- * Builds commit message generation prompt
217
- * Why: Used by prepare-commit-msg hook
218
- *
219
- * @param {Object} options - Build options
220
- * @param {Array<Object>} options.files - Array of changed files with diffs
221
- * @param {Object} options.stats - Staging statistics
222
- * @returns {Promise<string>} Complete commit message prompt
223
- *
224
- * Stats object structure:
225
- * {
226
- * totalFiles: number,
227
- * addedFiles: number,
228
- * modifiedFiles: number,
229
- * deletedFiles: number,
230
- * insertions: number,
231
- * deletions: number
232
- * }
233
- */
234
- const buildCommitMessagePrompt = async ({ files = [], stats = {} } = {}) => {
235
- logger.debug(
236
- 'prompt-builder - buildCommitMessagePrompt',
237
- 'Building commit message prompt',
238
- { fileCount: files.length, stats }
239
- );
240
-
241
- let prompt = `Generate a conventional commit message for the following changes.\n\n`;
242
-
243
- // Add statistics
244
- prompt += `=== STATISTICS ===\n`;
245
- prompt += `Files changed: ${stats.totalFiles || files.length}\n`;
246
- prompt += `Added: ${stats.addedFiles || 0}, Modified: ${stats.modifiedFiles || 0}, Deleted: ${stats.deletedFiles || 0}\n`;
247
- prompt += `Insertions: ${stats.insertions || 0}, Deletions: ${stats.deletions || 0}\n\n`;
248
-
249
- // Add file changes
250
- prompt += `=== CHANGED FILES ===\n`;
251
- files.forEach(({ path, diff }) => {
252
- prompt += `\n--- ${path} ---\n`;
253
- if (diff) {
254
- prompt += `${diff}\n`;
255
- }
256
- });
257
-
258
- // Add instructions
259
- prompt += `\n\n=== INSTRUCTIONS ===\n`;
260
- prompt += `Generate a concise commit message following Conventional Commits format:\n`;
261
- prompt += `- type: feat, fix, docs, style, refactor, test, chore\n`;
262
- prompt += `- Format: "type: description" or "type(scope): description"\n`;
263
- prompt += `- Description: Clear, imperative mood, no period at end\n`;
264
- prompt += `- Optional body: Detailed explanation if needed\n\n`;
265
- prompt += `Respond with ONLY the commit message, no explanations.\n`;
266
-
267
- logger.debug(
268
- 'prompt-builder - buildCommitMessagePrompt',
269
- 'Commit message prompt built',
270
- { promptLength: prompt.length }
271
- );
272
-
273
- return prompt;
274
- };
275
-
276
292
  export {
277
293
  PromptBuilderError,
278
294
  loadTemplate,
279
295
  replaceTemplate,
296
+ loadPrompt,
280
297
  formatFileSection,
281
- buildAnalysisPrompt,
282
- buildCommitMessagePrompt
298
+ buildAnalysisPrompt
283
299
  };
@@ -179,14 +179,20 @@ ${content}
179
179
  const generateResolutionPrompt = async (
180
180
  analysisResult,
181
181
  {
182
- outputPath = 'claude_resolution_prompt.md',
182
+ outputPath = null,
183
183
  templatePath = '.claude/CLAUDE_RESOLUTION_PROMPT.md',
184
184
  fileCount = 0
185
185
  } = {}
186
186
  ) => {
187
187
  // Why: Use repo root for absolute paths (works on Windows/PowerShell/Git Bash)
188
188
  const repoRoot = getRepoRoot();
189
- const absoluteOutputPath = path.join(repoRoot, outputPath);
189
+
190
+ // Load config to get default output path
191
+ const { getConfig } = await import('../config.js');
192
+ const config = await getConfig();
193
+ const finalOutputPath = outputPath || config.output.resolutionFile;
194
+
195
+ const absoluteOutputPath = path.join(repoRoot, finalOutputPath);
190
196
  const absoluteTemplatePath = path.join(repoRoot, templatePath);
191
197
 
192
198
  logger.debug(
@@ -226,6 +232,10 @@ const generateResolutionPrompt = async (
226
232
  .replace(/{{BLOCKING_ISSUES}}/g, issuesFormatted)
227
233
  .replace(/{{FILE_CONTENTS}}/g, fileContentsFormatted);
228
234
 
235
+ // Ensure output directory exists
236
+ const outputDir = path.dirname(absoluteOutputPath);
237
+ await fs.mkdir(outputDir, { recursive: true });
238
+
229
239
  // Write resolution prompt file
230
240
  await fs.writeFile(absoluteOutputPath, prompt, 'utf8');
231
241
 
package/package.json CHANGED
@@ -1,52 +1,51 @@
1
1
  {
2
- "name": "claude-git-hooks",
3
- "version": "2.1.0",
4
- "description": "Git hooks with Claude CLI for code analysis and automatic commit messages",
5
- "type": "module",
6
- "main": "lib/index.js",
7
- "bin": {
8
- "claude-hooks": "./bin/claude-hooks"
9
- },
10
- "scripts": {
11
- "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
12
- "test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch",
13
- "test:coverage": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage",
14
- "lint": "eslint lib/ bin/",
15
- "lint:fix": "eslint lib/ bin/ --fix",
16
- "format": "prettier --write \"lib/**/*.js\" \"bin/**\""
17
- },
18
- "keywords": [
19
- "git",
20
- "hooks",
21
- "claude",
22
- "ai",
23
- "code-review",
24
- "commit-messages",
25
- "pre-commit",
26
- "automation"
27
- ],
28
- "author": "Pablo Rovito",
29
- "license": "MIT",
30
- "repository": {
31
- "type": "git",
32
- "url": "https://github.com/pablorovito/claude-git-hooks.git"
33
- },
34
- "engines": {
35
- "node": ">=16.9.0"
36
- },
37
- "preferGlobal": true,
38
- "files": [
39
- "bin/",
40
- "lib/",
41
- "templates/",
42
- "README.md",
43
- "CHANGELOG.md",
44
- "LICENSE"
45
- ],
46
- "devDependencies": {
47
- "@types/jest": "^29.5.0",
48
- "eslint": "^8.57.0",
49
- "jest": "^29.7.0",
50
- "prettier": "^3.2.0"
51
- }
2
+ "name": "claude-git-hooks",
3
+ "version": "2.3.0",
4
+ "description": "Git hooks with Claude CLI for code analysis and automatic commit messages",
5
+ "type": "module",
6
+ "bin": {
7
+ "claude-hooks": "./bin/claude-hooks"
8
+ },
9
+ "scripts": {
10
+ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
11
+ "test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch",
12
+ "test:coverage": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage",
13
+ "lint": "eslint lib/ bin/",
14
+ "lint:fix": "eslint lib/ bin/ --fix",
15
+ "format": "prettier --write \"lib/**/*.js\" \"bin/**\""
16
+ },
17
+ "keywords": [
18
+ "git",
19
+ "hooks",
20
+ "claude",
21
+ "ai",
22
+ "code-review",
23
+ "commit-messages",
24
+ "pre-commit",
25
+ "automation"
26
+ ],
27
+ "author": "Pablo Rovito",
28
+ "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/pablorovito/claude-git-hooks.git"
32
+ },
33
+ "engines": {
34
+ "node": ">=16.9.0"
35
+ },
36
+ "preferGlobal": true,
37
+ "files": [
38
+ "bin/",
39
+ "lib/",
40
+ "templates/",
41
+ "README.md",
42
+ "CHANGELOG.md",
43
+ "LICENSE"
44
+ ],
45
+ "devDependencies": {
46
+ "@types/jest": "^29.5.0",
47
+ "eslint": "^8.57.0",
48
+ "jest": "^29.7.0",
49
+ "prettier": "^3.2.0"
50
+ }
52
51
  }
@@ -0,0 +1,33 @@
1
+ Analyze the following changes. CONTEXT: {{CONTEXT_DESCRIPTION}}
2
+ {{SUBAGENT_INSTRUCTION}}
3
+ Please generate:
4
+ 1. A concise and descriptive PR title (maximum 72 characters)
5
+ 2. A detailed PR description that includes:
6
+ - Summary of changes
7
+ - Motivation/context
8
+ - Type of change (feature/fix/refactor/docs/etc)
9
+ - Recommended testing
10
+ 3. A suggested branch name following the format: type/short-description (example: feature/add-user-auth, fix/memory-leak)
11
+
12
+ IMPORTANT: If these are local changes without push, the suggested branch name should be for creating a new branch from the current one.
13
+
14
+ Respond EXCLUSIVELY with a valid JSON with this structure:
15
+ ```json
16
+ {
17
+ "prTitle": "Interesting PR title",
18
+ "prDescription": "detailed PR description with markdown",
19
+ "suggestedBranchName": "type/suggested-branch-name",
20
+ "changeType": "feature|fix|refactor|docs|test|chore",
21
+ "breakingChanges": false,
22
+ "testingNotes": "notes on necessary testing or 'None'"
23
+ }
24
+ ```
25
+
26
+ ## COMMITS
27
+ {{COMMITS}}
28
+
29
+ ## CHANGED FILES
30
+ {{DIFF_FILES}}
31
+
32
+ ## FULL DIFF
33
+ {{FULL_DIFF}}
@@ -0,0 +1,24 @@
1
+ Analyze the following changes and generate a commit message following the Conventional Commits format.
2
+
3
+ Respond ONLY with a valid JSON:
4
+
5
+ ```json
6
+ {
7
+ "type": "feat|fix|docs|style|refactor|test|chore|ci|perf",
8
+ "scope": "optional scope (e.g.: api, frontend, db)",
9
+ "title": "short description in present tense (max 50 chars)",
10
+ "body": "optional detailed description"
11
+ }
12
+ ```
13
+
14
+ ## CHANGES TO ANALYZE
15
+
16
+ ### Modified files:
17
+ {{FILE_LIST}}
18
+
19
+ ### Summary of changes:
20
+ Files changed: {{FILE_COUNT}}
21
+ Insertions: {{INSERTIONS}}, Deletions: {{DELETIONS}}
22
+
23
+ ### Detailed diffs:
24
+ {{FILE_DIFFS}}
@@ -0,0 +1 @@
1
+ IMPORTANT OPTIMIZATION: When analyzing multiple files (3+), mentally organize your analysis into focused batches of {{BATCH_SIZE}} files at a time. This helps maintain quality while processing efficiently. For each file, perform thorough analysis following all guidelines and OUTPUT_SCHEMA requirements. After analyzing all files, consolidate into SINGLE JSON response: (1) merge all blockingIssues arrays, (2) merge all details arrays, (3) sum issue counts across all files, (4) worst-case metrics (lowest rating found), (5) QUALITY_GATE=FAILED if ANY file has blockers/criticals, (6) approved=false if any file is disapproved. Your response must be a single consolidated JSON object, not separate results per file.
@@ -0,0 +1,41 @@
1
+ {
2
+ "preset": null,
3
+ "analysis": {
4
+ "maxFileSize": 100000,
5
+ "maxFiles": 10,
6
+ "timeout": 120000,
7
+ "contextLines": 3,
8
+ "ignoreExtensions": []
9
+ },
10
+ "commitMessage": {
11
+ "autoKeyword": "auto",
12
+ "timeout": 180000
13
+ },
14
+ "subagents": {
15
+ "enabled": true,
16
+ "model": "haiku",
17
+ "batchSize": 3
18
+ },
19
+ "templates": {
20
+ "baseDir": ".claude",
21
+ "analysis": "CLAUDE_ANALYSIS_PROMPT_SONAR.md",
22
+ "guidelines": "CLAUDE_PRE_COMMIT_SONAR.md",
23
+ "commitMessage": "COMMIT_MESSAGE.md",
24
+ "analyzeDiff": "ANALYZE_DIFF.md",
25
+ "resolution": "CLAUDE_RESOLUTION_PROMPT.md",
26
+ "subagentInstruction": "SUBAGENT_INSTRUCTION.md"
27
+ },
28
+ "output": {
29
+ "outputDir": ".claude/out",
30
+ "debugFile": ".claude/out/debug-claude-response.json",
31
+ "resolutionFile": ".claude/out/claude_resolution_prompt.md",
32
+ "prAnalysisFile": ".claude/out/pr-analysis.json"
33
+ },
34
+ "system": {
35
+ "debug": false,
36
+ "wslCheckTimeout": 3000
37
+ },
38
+ "git": {
39
+ "diffFilter": "ACM"
40
+ }
41
+ }
@@ -0,0 +1,133 @@
1
+ You are analyzing a **{{PRESET_NAME}}** project with the following technology stack:
2
+
3
+ **Tech Stack:** {{TECH_STACK}}
4
+
5
+ **Analyzing files matching:** {{FILE_EXTENSIONS}}
6
+
7
+ ## Your Task
8
+
9
+ Perform a comprehensive code quality analysis focusing on these areas:
10
+
11
+ {{FOCUS_AREAS}}
12
+
13
+ ## Analysis Guidelines
14
+
15
+ 1. **Claude API Best Practices**:
16
+ - Proper use of Claude API endpoints
17
+ - Correct model selection (haiku/sonnet/opus)
18
+ - Token usage optimization
19
+ - Error handling for API failures
20
+ - Rate limiting considerations
21
+ - Timeout handling
22
+
23
+ 2. **Prompt Engineering**:
24
+ - Clear and specific instructions
25
+ - Well-structured prompts
26
+ - Appropriate context inclusion
27
+ - Effective use of examples
28
+ - Proper output format specifications
29
+ - Token-efficient prompting
30
+
31
+ 3. **CLI User Experience**:
32
+ - Clear, helpful error messages
33
+ - Appropriate use of colors/formatting
34
+ - Progress indicators for long operations
35
+ - Helpful usage instructions
36
+ - Graceful error recovery
37
+ - Cross-platform compatibility
38
+
39
+ 4. **Git Operations**:
40
+ - Safe git command execution
41
+ - Proper error handling
42
+ - Repository state validation
43
+ - Avoiding destructive operations
44
+ - Cross-platform path handling
45
+
46
+ 5. **Security**:
47
+ - API key protection (never log/expose)
48
+ - Secure credential storage
49
+ - Input validation
50
+ - Avoiding command injection
51
+ - Sensitive data handling in prompts
52
+
53
+ 6. **Code Quality**:
54
+ - Proper error handling
55
+ - Comprehensive logging
56
+ - Modular, reusable functions
57
+ - Clear documentation
58
+ - Maintainable code structure
59
+
60
+ ## Specific Checks
61
+
62
+ ### Claude API Usage
63
+ ✅ Using appropriate model for task (haiku for simple, sonnet for complex)
64
+ ✅ Implementing proper error handling (network, API, rate limit)
65
+ ✅ Token usage calculated and optimized
66
+ ✅ Prompts are well-structured and clear
67
+ ✅ Output parsing is robust
68
+ ✅ API keys never logged or exposed
69
+
70
+ ### Git Operations
71
+ ✅ Using proper git commands
72
+ ✅ Handling errors gracefully
73
+ ✅ Cross-platform path compatibility
74
+ ✅ Avoiding destructive operations without confirmation
75
+ ✅ Proper handling of special characters in filenames
76
+
77
+ ### Template Quality
78
+ ✅ Clear instructions for Claude
79
+ ✅ Well-defined output format
80
+ ✅ Appropriate context provided
81
+ ✅ Token-efficient design
82
+ ✅ Placeholders used correctly
83
+
84
+ ## Output Format
85
+
86
+ Respond with a valid JSON following the SonarQube format:
87
+
88
+ ```json
89
+ {
90
+ "QUALITY_GATE": "PASSED|FAILED",
91
+ "approved": true|false,
92
+ "metrics": {
93
+ "reliability": "A|B|C|D|E",
94
+ "security": "A|B|C|D|E",
95
+ "maintainability": "A|B|C|D|E",
96
+ "coverage": 0-100,
97
+ "duplications": 0-100,
98
+ "complexity": "number"
99
+ },
100
+ "issues": {
101
+ "blocker": 0,
102
+ "critical": 0,
103
+ "major": 0,
104
+ "minor": 0,
105
+ "info": 0
106
+ },
107
+ "details": [
108
+ {
109
+ "severity": "BLOCKER|CRITICAL|MAJOR|MINOR|INFO",
110
+ "type": "BUG|VULNERABILITY|CODE_SMELL|PROMPT_QUALITY",
111
+ "file": "path/to/file",
112
+ "line": 123,
113
+ "message": "Clear description of the issue"
114
+ }
115
+ ],
116
+ "securityHotspots": 0,
117
+ "blockingIssues": ["List of critical issues that must be fixed"]
118
+ }
119
+ ```
120
+
121
+ ## Analysis Rules
122
+
123
+ - **Block commit** if:
124
+ - Exposed API keys or secrets
125
+ - Security vulnerabilities
126
+ - Critical bugs in git operations
127
+ - Destructive operations without safeguards
128
+
129
+ - **Pass** if: Only minor issues, suggestions, or no issues
130
+
131
+ - Be constructive about prompt quality - suggest improvements
132
+ - Focus on safety and user experience
133
+ - Provide actionable, specific feedback with line numbers