claude-git-hooks 2.19.0 → 2.21.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.
@@ -0,0 +1,105 @@
1
+ /**
2
+ * File: diff-batch-info.js
3
+ * Purpose: Display intelligent diff-analysis orchestration config and speed telemetry
4
+ *
5
+ * Shows:
6
+ * - Orchestration model and threshold
7
+ * - Default analysis model from config
8
+ * - Per-model avg analysis times from telemetry
9
+ * - Avg orchestration overhead
10
+ * - Overall failure rate
11
+ */
12
+
13
+ import { getStatistics } from '../utils/telemetry.js';
14
+ import logger from '../utils/logger.js';
15
+
16
+ /**
17
+ * Runs the batch-info command
18
+ * Why: Surfaces orchestration configuration and speed telemetry so users can
19
+ * understand the adaptive batch system behavior without needing debug mode.
20
+ */
21
+ export async function runDiffBatchInfo() {
22
+ console.log(
23
+ '\n╔════════════════════════════════════════════════════════════════════╗'
24
+ );
25
+ console.log(
26
+ '║ INTELLIGENT ANALYSIS ORCHESTRATION INFO ║'
27
+ );
28
+ console.log(
29
+ '╚════════════════════════════════════════════════════════════════════╝\n'
30
+ );
31
+
32
+ console.log('━━━ ORCHESTRATION CONFIGURATION ━━━');
33
+ console.log(' Orchestration model: opus (internal, not user-configurable)');
34
+ console.log(' Orchestrator threshold: 3 files (commits with ≥3 files use intelligent grouping)');
35
+ console.log();
36
+
37
+ console.log('━━━ HOW IT WORKS ━━━');
38
+ console.log(' < 3 files: Sequential analysis (single Claude call)');
39
+ console.log(' ≥ 3 files: Orchestrator groups files semantically,');
40
+ console.log(' assigns model per batch, injects shared context');
41
+ console.log();
42
+
43
+ try {
44
+ const stats = await getStatistics(7);
45
+
46
+ if (!stats.enabled) {
47
+ console.log(' Telemetry is disabled — no speed data available.');
48
+ console.log(
49
+ ' To enable, ensure "system.telemetry" is not set to false in .claude/config.json'
50
+ );
51
+ console.log();
52
+ return;
53
+ }
54
+
55
+ if (stats.totalEvents === 0) {
56
+ console.log('━━━ SPEED TELEMETRY (last 7 days) ━━━');
57
+ console.log(' No telemetry data yet.');
58
+ console.log(
59
+ ' Run an analysis with ≥3 files to start collecting per-model timing data.'
60
+ );
61
+ console.log();
62
+ return;
63
+ }
64
+
65
+ console.log('━━━ SPEED TELEMETRY (last 7 days) ━━━');
66
+ console.log(` Total events: ${stats.totalEvents}`);
67
+ console.log(` Successful batches: ${stats.batchSuccesses}`);
68
+ console.log(` Failure rate: ${stats.failureRate}%`);
69
+ console.log();
70
+
71
+ if (Object.keys(stats.avgAnalysisTimeByModel).length > 0) {
72
+ console.log(' Average analysis time by model:');
73
+ for (const [model, ms] of Object.entries(stats.avgAnalysisTimeByModel)) {
74
+ const seconds = (ms / 1000).toFixed(1);
75
+ console.log(` ${model.padEnd(8)}: ${seconds}s`);
76
+ }
77
+ console.log();
78
+ }
79
+
80
+ if (stats.avgOrchestrationTime > 0) {
81
+ const orchSeconds = (stats.avgOrchestrationTime / 1000).toFixed(1);
82
+ console.log(` Avg orchestration overhead: ${orchSeconds}s`);
83
+ console.log(
84
+ ' (Orchestrator call for semantic grouping — one-time per commit)'
85
+ );
86
+ console.log();
87
+ }
88
+
89
+ if (Object.keys(stats.successesByHook).length > 0) {
90
+ console.log(' Successes by hook:');
91
+ for (const [hook, count] of Object.entries(stats.successesByHook)) {
92
+ console.log(` ${hook}: ${count}`);
93
+ }
94
+ console.log();
95
+ }
96
+ } catch (err) {
97
+ logger.debug('diff-batch-info - runDiffBatchInfo', 'Failed to load telemetry', err);
98
+ console.log(' Could not load telemetry data.');
99
+ console.log();
100
+ }
101
+
102
+ console.log('📂 Telemetry files: .claude/telemetry/');
103
+ console.log('💡 Use --debug true to see orchestrator decisions in real time');
104
+ console.log();
105
+ }
@@ -3,7 +3,7 @@
3
3
  * Purpose: Help, version display, and AI-powered help commands
4
4
  *
5
5
  * Features:
6
- * - Static help text (no args, --help, -h)
6
+ * - Dynamic help from command registry (no args, --help, -h)
7
7
  * - AI help: routes questions to Claude with CLAUDE.md as knowledge base
8
8
  * - Report issue: interactive issue creation guided by Claude
9
9
  */
@@ -17,6 +17,7 @@ import { loadPrompt } from '../utils/prompt-builder.js';
17
17
  import { fetchFileContent, fetchDirectoryListing, createIssue } from '../utils/github-api.js';
18
18
  import { promptMenu, promptEditField, promptConfirmation } from '../utils/interactive-ui.js';
19
19
  import logger from '../utils/logger.js';
20
+ import { commands } from '../cli-metadata.js';
20
21
 
21
22
  /**
22
23
  * Get claude-hooks source repo coordinates from package.json
@@ -67,56 +68,87 @@ export async function runShowHelp(args = []) {
67
68
  }
68
69
 
69
70
  /**
70
- * Display static help text
71
- * Why: Preserved original behavior for --help, -h, and no-args calls
71
+ * Display help text generated from command registry
72
+ * Why: Single source of truth adding a command to cli-metadata.js auto-updates help
72
73
  */
73
74
  export function showStaticHelp() {
75
+ const lines = formatCommandLines(commands);
76
+
74
77
  console.log(`
75
78
  Claude Git Hooks - Code analysis and automatic messages with Claude CLI
76
79
 
77
80
  Usage: claude-hooks <command> [options]
78
81
 
79
82
  Commands:
80
- analyze [--unstaged | --all] Analyze code interactively before committing
81
- analyze-diff [base] Analyze diff and generate PR metadata
82
- bump-version [type] [options] Bump version with CHANGELOG and Git tag
83
- <type>: major | minor | patch (optional for suffix-only operations)
84
- --dry-run Preview changes without applying
85
- --interactive Force file selection menu
86
- --no-commit Skip automatic commit
87
- --no-tag Skip Git tag creation
88
- --push Push tag to remote
89
- --remove-suffix Remove version suffix (no type required)
90
- --set-suffix <value> Set/replace version suffix (no type required)
91
- --suffix <value> Add version suffix (e.g., SNAPSHOT)
92
- --update-changelog [branch] Generate CHANGELOG entry
93
- create-pr [base] Create PR with auto-generated metadata
94
- --debug <true | false | status> Toggle debug mode
95
- disable [hook] Disable hooks (all or specific)
96
- enable [hook] Enable hooks (all or specific)
97
- generate-changelog [version] Generate CHANGELOG entry independently
98
- --base-branch <branch> Compare against branch (default: main)
99
- --release Mark as released
100
- help [question] Show help or ask AI a question
101
- --report-issue Create GitHub issue interactively
102
- install [options] Install hooks in current repository
103
- --force Reinstall even if already exist
104
- --skip-auth Skip Claude authentication check
105
- migrate-config Migrate legacy config to v2.8.0 format
106
- preset current Show current active preset
107
- presets List all available presets
108
- --set-preset <name> Set the active preset
109
- setup-github Configure GitHub token for PR creation
110
- status Show hook status
111
- telemetry [show | clear] View or clear telemetry data
112
- uninstall Remove hooks from repository
113
- update Update to latest version
114
- --version, -v Show current version
83
+ ${lines}
115
84
 
116
85
  More information: https://github.com/mscope-S-L/git-hooks
117
86
  `);
118
87
  }
119
88
 
89
+ /**
90
+ * Format command registry entries into aligned help lines
91
+ *
92
+ * @param {Array} cmds - Command entries from cli-metadata.js
93
+ * @returns {string} Formatted, alphabetically sorted command lines
94
+ */
95
+ function formatCommandLines(cmds) {
96
+ const entries = [];
97
+
98
+ for (const cmd of cmds) {
99
+ // Skip version/help aliases (shown via their primary entry)
100
+ if (cmd.name === 'version') continue;
101
+
102
+ // Build display name with args/aliases
103
+ let name = cmd.name;
104
+ if (cmd.aliases) {
105
+ name = `${cmd.name}, ${cmd.aliases.join(', ')}`;
106
+ }
107
+ if (cmd.args) {
108
+ const argLabel = cmd.args.values
109
+ ? cmd.args.values.join(' | ')
110
+ : cmd.args.name;
111
+ name += ` [${argLabel}]`;
112
+ }
113
+ if (cmd.subcommands) {
114
+ name += ` [${cmd.subcommands.join(' | ')}]`;
115
+ }
116
+ if (cmd.flags) {
117
+ name += ' [options]';
118
+ }
119
+
120
+ entries.push({ name, description: cmd.description, flags: cmd.flags });
121
+ }
122
+
123
+ // Sort alphabetically (strip leading -- for comparison)
124
+ entries.sort((a, b) => {
125
+ const aKey = a.name.replace(/^--/, '');
126
+ const bKey = b.name.replace(/^--/, '');
127
+ return aKey.localeCompare(bKey);
128
+ });
129
+
130
+ // Calculate padding
131
+ const maxLen = Math.max(...entries.map((e) => e.name.length));
132
+
133
+ const lines = [];
134
+ for (const entry of entries) {
135
+ const padding = ' '.repeat(maxLen - entry.name.length + 4);
136
+ lines.push(` ${entry.name}${padding}${entry.description}`);
137
+
138
+ // Add flag lines indented under command
139
+ if (entry.flags) {
140
+ const flagEntries = Object.entries(entry.flags).sort(([a], [b]) => a.localeCompare(b));
141
+ for (const [flag, meta] of flagEntries) {
142
+ const flagName = meta.takesValue ? `${flag} <value>` : flag;
143
+ const flagPad = ' '.repeat(maxLen - flagName.length + 2);
144
+ lines.push(` ${flagName}${flagPad}${meta.description}`);
145
+ }
146
+ }
147
+ }
148
+
149
+ return lines.join('\n');
150
+ }
151
+
120
152
  /**
121
153
  * Print AI help response with version source footer
122
154
  *
@@ -327,11 +327,6 @@ export function extractLegacySettings(rawConfig) {
327
327
  }
328
328
  }
329
329
 
330
- // Subagent batchSize (allowed)
331
- if (rawConfig.subagents?.batchSize !== undefined) {
332
- allowedOverrides.subagents = { batchSize: rawConfig.subagents.batchSize };
333
- }
334
-
335
330
  // Advanced params (preserved with warning in manual migration)
336
331
  if (rawConfig.analysis?.ignoreExtensions !== undefined) {
337
332
  if (!allowedOverrides.analysis) allowedOverrides.analysis = {};
@@ -343,11 +338,6 @@ export function extractLegacySettings(rawConfig) {
343
338
  allowedOverrides.commitMessage.taskIdPattern = rawConfig.commitMessage.taskIdPattern;
344
339
  }
345
340
 
346
- if (rawConfig.subagents?.model !== undefined) {
347
- if (!allowedOverrides.subagents) allowedOverrides.subagents = {};
348
- allowedOverrides.subagents.model = rawConfig.subagents.model;
349
- }
350
-
351
341
  return allowedOverrides;
352
342
  }
353
343
 
@@ -0,0 +1,96 @@
1
+ /**
2
+ * File: setup-linear.js
3
+ * Purpose: Interactive Linear authentication setup command
4
+ *
5
+ * Handles:
6
+ * - Checking existing token
7
+ * - Prompting user for new token
8
+ * - Validating token via Linear API
9
+ * - Saving token to .claude/settings.local.json
10
+ */
11
+
12
+ import { testConnection, loadLinearToken } from '../utils/linear-connector.js';
13
+ import { saveToken } from '../utils/token-store.js';
14
+ import {
15
+ promptConfirmation,
16
+ promptEditField,
17
+ showSuccess,
18
+ showError,
19
+ showInfo,
20
+ showWarning
21
+ } from '../utils/interactive-ui.js';
22
+ import logger from '../utils/logger.js';
23
+
24
+ /**
25
+ * Run Linear authentication setup
26
+ * Why: Interactive flow to configure Linear token for PR analysis enrichment
27
+ *
28
+ * @returns {Promise<void>}
29
+ */
30
+ export async function runSetupLinear() {
31
+ showInfo('Linear Authentication Setup');
32
+
33
+ // Check existing token
34
+ const existingToken = loadLinearToken();
35
+ if (existingToken) {
36
+ showInfo('Existing Linear token found. Validating...');
37
+
38
+ const healthy = await testConnection(existingToken);
39
+ if (healthy) {
40
+ showSuccess('Linear token is valid and connected.');
41
+
42
+ const reconfigure = await promptConfirmation('Configure a different token?', false);
43
+ if (!reconfigure) {
44
+ return;
45
+ }
46
+ } else {
47
+ showWarning('Existing token is invalid or expired.');
48
+ }
49
+ }
50
+
51
+ // Show instructions
52
+ logger.info('Create a Linear API key:');
53
+ logger.info(' 1. Go to: https://linear.app/settings/api');
54
+ logger.info(' 2. Click "Create key"');
55
+ logger.info(' 3. Give it a label (e.g., "claude-hooks")');
56
+ logger.info(' 4. Copy the key (starts with lin_api_...)');
57
+
58
+ // Prompt for token
59
+ const token = await promptEditField('Paste your Linear API key (lin_api_...)', '');
60
+
61
+ if (!token || token.trim() === '') {
62
+ showWarning('No token provided. Setup cancelled.');
63
+ return;
64
+ }
65
+
66
+ const trimmedToken = token.trim();
67
+
68
+ // Basic format check
69
+ if (!trimmedToken.startsWith('lin_api_')) {
70
+ showWarning('Token format looks unusual (expected lin_api_...)');
71
+ const proceed = await promptConfirmation('Continue anyway?', false);
72
+ if (!proceed) {
73
+ return;
74
+ }
75
+ }
76
+
77
+ // Save token
78
+ const saveResult = saveToken('linearToken', trimmedToken);
79
+ if (!saveResult.success) {
80
+ showError(`Failed to save token: ${saveResult.error}`);
81
+ return;
82
+ }
83
+ showSuccess(`Token saved to ${saveResult.path}`);
84
+
85
+ // Validate with Linear API
86
+ showInfo('Validating token...');
87
+
88
+ const healthy = await testConnection(trimmedToken);
89
+ if (healthy) {
90
+ showSuccess('Linear connection verified.');
91
+ } else {
92
+ showWarning('Token validation failed - may not work correctly');
93
+ }
94
+
95
+ showSuccess('Setup complete! Linear ticket context will be used in: claude-hooks analyze-pr');
96
+ }
package/lib/config.js CHANGED
@@ -6,9 +6,8 @@
6
6
  *
7
7
  * v2.8.0 Changes:
8
8
  * - Removed 21 redundant parameters (hardcoded sensible defaults)
9
- * - Only 5 user-configurable parameters remain
10
- * - Preset can override: subagents.batchSize
11
- * - User can override: github.pr.*, subagents.batchSize
9
+ * - Only 4 user-configurable parameters remain
10
+ * - User can override: github.pr.*
12
11
  * - Advanced params moved to config.advanced.example.json
13
12
  *
14
13
  * User-configurable:
@@ -16,12 +15,10 @@
16
15
  * - github.pr.defaultBase
17
16
  * - github.pr.reviewers
18
17
  * - github.pr.labelRules
19
- * - subagents.batchSize
20
18
  *
21
19
  * Advanced (in example file only):
22
20
  * - analysis.ignoreExtensions
23
21
  * - commitMessage.taskIdPattern
24
- * - subagents.model
25
22
  */
26
23
 
27
24
  import fs from 'fs';
@@ -35,7 +32,7 @@ import logger from './utils/logger.js';
35
32
  const HARDCODED = {
36
33
  analysis: {
37
34
  maxFileSize: 1000000, // 1MB - sufficient for most files
38
- maxFiles: 20, // Reasonable limit per commit
35
+ maxFiles: 30, // Reasonable limit per commit
39
36
  timeout: 300000, // 5 minutes - adequate for Claude API
40
37
  contextLines: 3, // Git default
41
38
  ignoreExtensions: [] // Can be set in advanced config only
@@ -46,9 +43,7 @@ const HARDCODED = {
46
43
  taskIdPattern: '([A-Z]{1,3}[-\\s]\\d{3,5})' // Jira/GitHub/Linear pattern
47
44
  },
48
45
  subagents: {
49
- enabled: true, // Enable by default (faster analysis)
50
- model: 'haiku', // Fast and cost-effective
51
- batchSize: 3 // Reasonable parallelization
46
+ enabled: true // Enable by default (faster analysis via orchestration)
52
47
  },
53
48
  templates: {
54
49
  baseDir: '.claude/prompts',
@@ -57,7 +52,6 @@ const HARDCODED = {
57
52
  commitMessage: 'COMMIT_MESSAGE.md',
58
53
  analyzeDiff: 'ANALYZE_DIFF.md',
59
54
  resolution: 'CLAUDE_RESOLUTION_PROMPT.md',
60
- subagentInstruction: 'SUBAGENT_INSTRUCTION.md',
61
55
  createGithubPR: 'CREATE_GITHUB_PR.md'
62
56
  },
63
57
  output: {
@@ -76,6 +70,21 @@ const HARDCODED = {
76
70
  },
77
71
  github: {
78
72
  enabled: true // Always enabled
73
+ },
74
+ prAnalysis: {
75
+ model: 'sonnet',
76
+ timeout: 300000, // 5 minutes
77
+ inlineCategories: ['bug', 'security', 'performance', 'hotspot'],
78
+ generalCategories: [
79
+ 'ticket-alignment',
80
+ 'scope',
81
+ 'style',
82
+ 'good-practice',
83
+ 'extensibility',
84
+ 'observability',
85
+ 'documentation',
86
+ 'testing'
87
+ ]
79
88
  }
80
89
  };
81
90
 
@@ -106,10 +115,6 @@ const defaults = {
106
115
  }
107
116
  },
108
117
 
109
- // Subagent configuration (preset can override)
110
- subagents: {
111
- batchSize: 3 // Files per parallel batch
112
- }
113
118
  };
114
119
 
115
120
  /**
@@ -196,8 +201,8 @@ const loadUserConfig = async (baseDir = process.cwd()) => {
196
201
 
197
202
  /**
198
203
  * Extracts only allowed parameters from legacy config
199
- * v2.8.0 only allows: github.pr.*, subagents.batchSize
200
- * Advanced: analysis.ignoreExtensions, commitMessage.taskIdPattern, subagents.model
204
+ * Allowed: github.pr.*
205
+ * Advanced: analysis.ignoreExtensions, commitMessage.taskIdPattern
201
206
  *
202
207
  * @param {Object} legacyConfig - Legacy format config
203
208
  * @returns {Object} Allowed parameters only
@@ -219,11 +224,6 @@ const extractAllowedParams = (legacyConfig) => {
219
224
  }
220
225
  }
221
226
 
222
- // Subagent batchSize (allowed)
223
- if (legacyConfig.subagents?.batchSize !== undefined) {
224
- allowed.subagents = { batchSize: legacyConfig.subagents.batchSize };
225
- }
226
-
227
227
  // Advanced params (allowed but warn)
228
228
  if (legacyConfig.analysis?.ignoreExtensions !== undefined) {
229
229
  if (!allowed.analysis) allowed.analysis = {};
@@ -237,12 +237,6 @@ const extractAllowedParams = (legacyConfig) => {
237
237
  logger.warning('ℹ️ Using advanced parameter: commitMessage.taskIdPattern');
238
238
  }
239
239
 
240
- if (legacyConfig.subagents?.model !== undefined) {
241
- if (!allowed.subagents) allowed.subagents = {};
242
- allowed.subagents.model = legacyConfig.subagents.model;
243
- logger.warning('ℹ️ Using advanced parameter: subagents.model');
244
- }
245
-
246
240
  return allowed;
247
241
  };
248
242
 
@@ -21,10 +21,10 @@
21
21
 
22
22
  import { getStagedFiles, getRepoRoot } from '../utils/git-operations.js';
23
23
  import { filterFiles } from '../utils/file-operations.js';
24
- import { buildFilesData, runAnalysis, displayResults } from '../utils/analysis-engine.js';
24
+ import { buildFilesData, runAnalysis, displayResults, hasAnyIssues } from '../utils/analysis-engine.js';
25
25
  import { generateResolutionPrompt, shouldGeneratePrompt } from '../utils/resolution-prompt.js';
26
26
  import { loadPreset } from '../utils/preset-loader.js';
27
- import { getVersion, calculateBatches } from '../utils/package-info.js';
27
+ import { getVersion } from '../utils/package-info.js';
28
28
  import logger from '../utils/logger.js';
29
29
  import { getConfig } from '../config.js';
30
30
 
@@ -145,21 +145,9 @@ const main = async () => {
145
145
  // Step 4: Log analysis configuration
146
146
  logger.info(`Sending ${filesData.length} files for review...`);
147
147
 
148
- // Display subagent configuration
149
- const subagentsEnabled = config.subagents?.enabled !== false;
150
- const subagentModel = config.subagents?.model || 'haiku';
151
- const batchSize = config.subagents?.batchSize || 3;
152
-
153
- if (subagentsEnabled && filesData.length >= 3) {
154
- const { numBatches, shouldShowBatches } = calculateBatches(filesData.length, batchSize);
155
- console.log(
156
- `⚡ Batch optimization: ${subagentModel} model, ${batchSize} files per batch`
157
- );
158
- if (shouldShowBatches) {
159
- console.log(
160
- `📊 Analyzing ${filesData.length} files in ${numBatches} batch${numBatches > 1 ? 'es' : ''}`
161
- );
162
- }
148
+ // Display analysis routing hint
149
+ if (filesData.length >= 3) {
150
+ logger.info('⚡ Intelligent orchestration: grouping files and assigning models');
163
151
  }
164
152
 
165
153
  // Step 5: Run analysis using shared engine
@@ -171,6 +159,44 @@ const main = async () => {
171
159
  // Step 6: Display results using shared function
172
160
  displayResults(result);
173
161
 
162
+ // Step 6.5: Judge — auto-fix all issues
163
+ if (config.judge?.enabled !== false && hasAnyIssues(result)) {
164
+ try {
165
+ const { judgeAndFix } = await import('../utils/judge.js');
166
+ const judgeResult = await judgeAndFix(result, filesData, config);
167
+
168
+ // Update result with remaining issues (fixed + false positives removed)
169
+ result.blockingIssues = judgeResult.remainingIssues.filter(
170
+ (i) =>
171
+ ['blocker', 'critical'].includes(
172
+ (i.severity || '').toLowerCase()
173
+ )
174
+ );
175
+ result.details = judgeResult.remainingIssues;
176
+
177
+ // Recalculate quality gate — pass only if ALL issues resolved
178
+ if (judgeResult.remainingIssues.length === 0) {
179
+ result.issues = {
180
+ blocker: 0,
181
+ critical: 0,
182
+ major: 0,
183
+ minor: 0,
184
+ info: 0
185
+ };
186
+ result.QUALITY_GATE = 'PASSED';
187
+ result.approved = true;
188
+ } else {
189
+ result.QUALITY_GATE = 'FAILED';
190
+ result.approved = false;
191
+ }
192
+ } catch (err) {
193
+ logger.warning(`Judge failed: ${err.message}`);
194
+ logger.warning('Commit blocked — judge could not verify issues');
195
+ result.QUALITY_GATE = 'FAILED';
196
+ result.approved = false;
197
+ }
198
+ }
199
+
174
200
  // Step 7: Check quality gate
175
201
  const qualityGatePassed = result.QUALITY_GATE === 'PASSED';
176
202
  const approved = result.approved !== false;
@@ -21,7 +21,7 @@ import fs from 'fs/promises';
21
21
  import { getStagedFiles, getStagedStats, getFileDiff } from '../utils/git-operations.js';
22
22
  import { analyzeCode } from '../utils/claude-client.js';
23
23
  import { loadPrompt } from '../utils/prompt-builder.js';
24
- import { getVersion, calculateBatches } from '../utils/package-info.js';
24
+ import { getVersion } from '../utils/package-info.js';
25
25
  import logger from '../utils/logger.js';
26
26
  import { getConfig } from '../config.js';
27
27
  import { getOrPromptTaskId, formatWithTaskId } from '../utils/task-id.js';
@@ -152,14 +152,7 @@ const main = async () => {
152
152
 
153
153
  // Display configuration info
154
154
  const version = await getVersion();
155
- const subagentsEnabled = config.subagents?.enabled || false;
156
- const subagentModel = config.subagents?.model || 'haiku';
157
- const batchSize = config.subagents?.batchSize || 3;
158
-
159
155
  console.log(`\n🤖 claude-git-hooks v${version}`);
160
- if (subagentsEnabled) {
161
- console.log(`⚡ Parallel analysis: ${subagentModel} model, batch size ${batchSize}`);
162
- }
163
156
 
164
157
  logger.info('Generating commit message automatically...');
165
158
 
@@ -235,28 +228,14 @@ const main = async () => {
235
228
 
236
229
  logger.debug('prepare-commit-msg - main', 'Prompt built', { promptLength: prompt.length });
237
230
 
238
- // Calculate batches if subagents enabled and applicable
239
- if (subagentsEnabled && filesData.length >= 3) {
240
- const { numBatches, shouldShowBatches } = calculateBatches(filesData.length, batchSize);
241
- if (shouldShowBatches) {
242
- console.log(
243
- `📊 Analyzing ${filesData.length} files in ${numBatches} batch${numBatches > 1 ? 'es' : ''}`
244
- );
245
- }
246
- }
247
-
248
231
  // Generate message with Claude
249
232
  logger.info('Sending to Claude...');
250
233
 
251
234
  // Build telemetry context
252
235
  const telemetryContext = {
253
236
  fileCount: filesData.length,
254
- batchSize: config.subagents?.batchSize || 3,
255
- totalBatches:
256
- subagentsEnabled && filesData.length >= 3
257
- ? Math.ceil(filesData.length / (config.subagents?.batchSize || 3))
258
- : 1,
259
- model: subagentModel,
237
+ batchSize: filesData.length,
238
+ totalBatches: 1,
260
239
  hook: 'prepare-commit-msg'
261
240
  };
262
241