claude-git-hooks 1.5.5 → 2.0.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.
- package/CHANGELOG.md +53 -0
- package/README.md +90 -35
- package/bin/claude-hooks +97 -188
- package/lib/hooks/pre-commit.js +335 -0
- package/lib/hooks/prepare-commit-msg.js +283 -0
- package/lib/utils/claude-client.js +373 -0
- package/lib/utils/file-operations.js +409 -0
- package/lib/utils/git-operations.js +341 -0
- package/lib/utils/logger.js +141 -0
- package/lib/utils/prompt-builder.js +283 -0
- package/lib/utils/resolution-prompt.js +291 -0
- package/package.json +52 -40
- package/templates/pre-commit +58 -445
- package/templates/prepare-commit-msg +61 -151
package/bin/claude-hooks
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
import { execSync, spawn } from 'child_process';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import os from 'os';
|
|
7
|
+
import readline from 'readline';
|
|
8
|
+
import https from 'https';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import { dirname } from 'path';
|
|
11
|
+
import { executeClaude, extractJSON } from '../lib/utils/claude-client.js';
|
|
12
|
+
|
|
13
|
+
// Why: ES6 modules don't have __dirname, need to recreate it
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = dirname(__filename);
|
|
16
|
+
|
|
17
|
+
// Helper to read package.json
|
|
18
|
+
// Why: ES6 modules can't use require() for JSON files
|
|
19
|
+
const getPackageJson = () => {
|
|
20
|
+
const packagePath = path.join(__dirname, '..', 'package.json');
|
|
21
|
+
return JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
|
22
|
+
};
|
|
9
23
|
|
|
10
24
|
// Function to get the latest version from NPM
|
|
11
25
|
function getLatestVersion(packageName) {
|
|
@@ -40,7 +54,7 @@ function getLatestVersion(packageName) {
|
|
|
40
54
|
// Function to check version (used by hooks)
|
|
41
55
|
async function checkVersionAndPromptUpdate() {
|
|
42
56
|
try {
|
|
43
|
-
const currentVersion =
|
|
57
|
+
const currentVersion = getPackageJson().version;
|
|
44
58
|
const latestVersion = await getLatestVersion('claude-git-hooks');
|
|
45
59
|
|
|
46
60
|
if (currentVersion === latestVersion) {
|
|
@@ -82,11 +96,6 @@ async function checkVersionAndPromptUpdate() {
|
|
|
82
96
|
}
|
|
83
97
|
}
|
|
84
98
|
|
|
85
|
-
// Export for use in hooks
|
|
86
|
-
if (typeof module !== 'undefined' && module.exports) {
|
|
87
|
-
module.exports = { checkVersionAndPromptUpdate };
|
|
88
|
-
}
|
|
89
|
-
|
|
90
99
|
// Colors for output
|
|
91
100
|
const colors = {
|
|
92
101
|
reset: '\x1b[0m',
|
|
@@ -142,45 +151,6 @@ function readPassword(prompt) {
|
|
|
142
151
|
});
|
|
143
152
|
}
|
|
144
153
|
|
|
145
|
-
// Check if sudo password is correct
|
|
146
|
-
function testSudoPassword(password) {
|
|
147
|
-
try {
|
|
148
|
-
execSync('echo "' + password + '" | sudo -S true', {
|
|
149
|
-
stdio: 'ignore',
|
|
150
|
-
timeout: 5000
|
|
151
|
-
});
|
|
152
|
-
return true;
|
|
153
|
-
} catch (e) {
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Install package with automatic sudo
|
|
159
|
-
function installPackage(packageName, sudoPassword = null) {
|
|
160
|
-
try {
|
|
161
|
-
if (sudoPassword) {
|
|
162
|
-
if (os.platform() === 'linux') {
|
|
163
|
-
execSync(`echo "${sudoPassword}" | sudo -S apt-get update && echo "${sudoPassword}" | sudo -S apt-get install -y ${packageName}`, {
|
|
164
|
-
stdio: 'inherit'
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
} else {
|
|
168
|
-
if (os.platform() === 'linux') {
|
|
169
|
-
execSync(`sudo apt-get update && sudo apt-get install -y ${packageName}`, {
|
|
170
|
-
stdio: 'inherit'
|
|
171
|
-
});
|
|
172
|
-
} else if (os.platform() === 'darwin') {
|
|
173
|
-
execSync(`brew install ${packageName}`, {
|
|
174
|
-
stdio: 'inherit'
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
return true;
|
|
179
|
-
} catch (e) {
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
154
|
// Entertainment system
|
|
185
155
|
class Entertainment {
|
|
186
156
|
static jokes = [
|
|
@@ -368,25 +338,9 @@ async function install(args) {
|
|
|
368
338
|
info('Installing Claude Git Hooks...');
|
|
369
339
|
}
|
|
370
340
|
|
|
371
|
-
//
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
const needsInstall = await checkIfInstallationNeeded();
|
|
375
|
-
if (needsInstall) {
|
|
376
|
-
info('Sudo access is needed for automatic dependency installation, please enter password');
|
|
377
|
-
sudoPassword = await readPassword('Enter your Ubuntu password for sudo: ');
|
|
378
|
-
|
|
379
|
-
if (sudoPassword && !testSudoPassword(sudoPassword)) {
|
|
380
|
-
warning('Incorrect password. Continuing without automatic installation.');
|
|
381
|
-
sudoPassword = null;
|
|
382
|
-
} else if (sudoPassword) {
|
|
383
|
-
success('Password verified. Proceeding with automatic installation.');
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// Check dependencies with automatic installation
|
|
389
|
-
await checkAndInstallDependencies(sudoPassword, skipAuth);
|
|
341
|
+
// v2.0.0+: No sudo needed (pure Node.js, no system packages required)
|
|
342
|
+
// Check dependencies
|
|
343
|
+
await checkAndInstallDependencies(null, skipAuth);
|
|
390
344
|
|
|
391
345
|
const templatesPath = getTemplatesPath();
|
|
392
346
|
const hooksPath = '.git/hooks';
|
|
@@ -396,6 +350,15 @@ async function install(args) {
|
|
|
396
350
|
fs.mkdirSync(hooksPath, { recursive: true });
|
|
397
351
|
}
|
|
398
352
|
|
|
353
|
+
// Helper function to copy file with LF line endings
|
|
354
|
+
// Why: Bash scripts must have LF (Unix) line endings, not CRLF (Windows)
|
|
355
|
+
const copyWithLF = (sourcePath, destPath) => {
|
|
356
|
+
let content = fs.readFileSync(sourcePath, 'utf8');
|
|
357
|
+
// Convert CRLF to LF
|
|
358
|
+
content = content.replace(/\r\n/g, '\n');
|
|
359
|
+
fs.writeFileSync(destPath, content, 'utf8');
|
|
360
|
+
};
|
|
361
|
+
|
|
399
362
|
// Hooks to install
|
|
400
363
|
const hooks = ['pre-commit', 'prepare-commit-msg'];
|
|
401
364
|
|
|
@@ -410,18 +373,18 @@ async function install(args) {
|
|
|
410
373
|
info(`Backup created: ${backupPath}`);
|
|
411
374
|
}
|
|
412
375
|
|
|
413
|
-
// Copy hook
|
|
414
|
-
|
|
376
|
+
// Copy hook with LF line endings (critical for bash)
|
|
377
|
+
copyWithLF(sourcePath, destPath);
|
|
415
378
|
fs.chmodSync(destPath, '755');
|
|
416
379
|
success(`${hook} installed`);
|
|
417
380
|
});
|
|
418
381
|
|
|
419
|
-
// Copy version verification script
|
|
382
|
+
// Copy version verification script with LF line endings
|
|
420
383
|
const checkVersionSource = path.join(templatesPath, 'check-version.sh');
|
|
421
384
|
const checkVersionDest = path.join(hooksPath, 'check-version.sh');
|
|
422
385
|
|
|
423
386
|
if (fs.existsSync(checkVersionSource)) {
|
|
424
|
-
|
|
387
|
+
copyWithLF(checkVersionSource, checkVersionDest);
|
|
425
388
|
fs.chmodSync(checkVersionDest, '755');
|
|
426
389
|
success('Version verification script installed');
|
|
427
390
|
}
|
|
@@ -500,41 +463,7 @@ async function checkAndInstallDependencies(sudoPassword = null, skipAuth = false
|
|
|
500
463
|
error('npm is not installed.');
|
|
501
464
|
}
|
|
502
465
|
|
|
503
|
-
//
|
|
504
|
-
try {
|
|
505
|
-
const jqVersion = execSync('jq --version', { encoding: 'utf8' }).trim();
|
|
506
|
-
success(`jq ${jqVersion}`);
|
|
507
|
-
} catch (e) {
|
|
508
|
-
warning('jq is not installed. Installing...');
|
|
509
|
-
if (installPackage('jq', sudoPassword)) {
|
|
510
|
-
success('jq installed successfully');
|
|
511
|
-
} else {
|
|
512
|
-
warning('Could not install jq automatically');
|
|
513
|
-
if (os.platform() === 'linux') {
|
|
514
|
-
console.log('Install it manually with: sudo apt install jq');
|
|
515
|
-
} else if (os.platform() === 'darwin') {
|
|
516
|
-
console.log('Install it manually with: brew install jq');
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// Check and install curl
|
|
522
|
-
try {
|
|
523
|
-
const curlVersion = execSync('curl --version', { encoding: 'utf8' }).split('\n')[0];
|
|
524
|
-
success(`curl ${curlVersion.split(' ')[1]}`);
|
|
525
|
-
} catch (e) {
|
|
526
|
-
warning('curl is not installed. Installing...');
|
|
527
|
-
if (installPackage('curl', sudoPassword)) {
|
|
528
|
-
success('curl installed successfully');
|
|
529
|
-
} else {
|
|
530
|
-
warning('Could not install curl automatically');
|
|
531
|
-
if (os.platform() === 'linux') {
|
|
532
|
-
console.log('Install it manually with: sudo apt install curl');
|
|
533
|
-
} else if (os.platform() === 'darwin') {
|
|
534
|
-
console.log('Install it manually with: brew install curl');
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
}
|
|
466
|
+
// v2.0.0+: jq and curl are no longer needed (pure Node.js implementation)
|
|
538
467
|
|
|
539
468
|
// Check Git
|
|
540
469
|
try {
|
|
@@ -544,23 +473,7 @@ async function checkAndInstallDependencies(sudoPassword = null, skipAuth = false
|
|
|
544
473
|
error('Git is not installed. Install Git and try again.');
|
|
545
474
|
}
|
|
546
475
|
|
|
547
|
-
//
|
|
548
|
-
const unixTools = ['sed', 'awk', 'grep', 'head', 'tail', 'stat', 'tput'];
|
|
549
|
-
const missingTools = [];
|
|
550
|
-
|
|
551
|
-
unixTools.forEach(tool => {
|
|
552
|
-
try {
|
|
553
|
-
execSync(`which ${tool}`, { stdio: 'ignore' });
|
|
554
|
-
} catch (e) {
|
|
555
|
-
missingTools.push(tool);
|
|
556
|
-
}
|
|
557
|
-
});
|
|
558
|
-
|
|
559
|
-
if (missingTools.length === 0) {
|
|
560
|
-
success('Standard Unix tools verified');
|
|
561
|
-
} else {
|
|
562
|
-
error(`Missing standard Unix tools: ${missingTools.join(', ')}. Retry installation in an Ubuntu console`);
|
|
563
|
-
}
|
|
476
|
+
// v2.0.0+: Unix tools (sed, awk, grep, etc.) no longer needed (pure Node.js implementation)
|
|
564
477
|
|
|
565
478
|
// Check and install Claude CLI
|
|
566
479
|
await checkAndInstallClaude();
|
|
@@ -576,21 +489,25 @@ async function checkAndInstallDependencies(sudoPassword = null, skipAuth = false
|
|
|
576
489
|
sudoPassword = null;
|
|
577
490
|
}
|
|
578
491
|
|
|
492
|
+
// Detect if running on Windows
|
|
493
|
+
// Why: Need to use 'wsl claude' instead of 'claude' on Windows
|
|
494
|
+
function isWindows() {
|
|
495
|
+
return os.platform() === 'win32' || process.env.OS === 'Windows_NT';
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Get Claude command based on platform
|
|
499
|
+
// Why: On Windows, Claude CLI runs in WSL, so we need 'wsl claude'
|
|
500
|
+
function getClaudeCommand() {
|
|
501
|
+
return isWindows() ? 'wsl claude' : 'claude';
|
|
502
|
+
}
|
|
503
|
+
|
|
579
504
|
// Check if we need to install dependencies
|
|
580
505
|
async function checkIfInstallationNeeded() {
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
for (const dep of dependencies) {
|
|
584
|
-
try {
|
|
585
|
-
execSync(`which ${dep}`, { stdio: 'ignore' });
|
|
586
|
-
} catch (e) {
|
|
587
|
-
return true; // Needs installation
|
|
588
|
-
}
|
|
589
|
-
}
|
|
506
|
+
// v2.0.0+: Only check Claude CLI (jq and curl no longer needed)
|
|
507
|
+
const claudeCmd = getClaudeCommand();
|
|
590
508
|
|
|
591
|
-
// Verificar Claude CLI
|
|
592
509
|
try {
|
|
593
|
-
execSync(
|
|
510
|
+
execSync(`${claudeCmd} --version`, { stdio: 'ignore' });
|
|
594
511
|
} catch (e) {
|
|
595
512
|
return true; // Needs Claude installation
|
|
596
513
|
}
|
|
@@ -598,19 +515,28 @@ async function checkIfInstallationNeeded() {
|
|
|
598
515
|
return false;
|
|
599
516
|
}
|
|
600
517
|
|
|
601
|
-
// Check
|
|
518
|
+
// Check Claude CLI availability
|
|
602
519
|
async function checkAndInstallClaude() {
|
|
520
|
+
const claudeCmd = getClaudeCommand();
|
|
521
|
+
const platform = isWindows() ? 'Windows (via WSL)' : os.platform();
|
|
522
|
+
|
|
603
523
|
try {
|
|
604
|
-
execSync(
|
|
605
|
-
success(
|
|
524
|
+
execSync(`${claudeCmd} --version`, { stdio: 'ignore' });
|
|
525
|
+
success(`Claude CLI detected (${platform})`);
|
|
606
526
|
} catch (e) {
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
527
|
+
error(`Claude CLI not detected on ${platform}`);
|
|
528
|
+
|
|
529
|
+
if (isWindows()) {
|
|
530
|
+
console.log('\n⚠️ On Windows, Claude CLI must be installed in WSL:');
|
|
531
|
+
console.log('1. Open WSL terminal (wsl or Ubuntu from Start Menu)');
|
|
532
|
+
console.log('2. Follow installation at: https://docs.anthropic.com/claude/docs/claude-cli');
|
|
533
|
+
console.log('3. Verify with: wsl claude --version');
|
|
534
|
+
} else {
|
|
535
|
+
console.log('\nClaude CLI installation: https://docs.anthropic.com/claude/docs/claude-cli');
|
|
613
536
|
}
|
|
537
|
+
|
|
538
|
+
console.log('\nAfter installation, run: claude-hooks install --force');
|
|
539
|
+
process.exit(1);
|
|
614
540
|
}
|
|
615
541
|
}
|
|
616
542
|
|
|
@@ -618,9 +544,15 @@ async function checkAndInstallClaude() {
|
|
|
618
544
|
async function checkClaudeAuth() {
|
|
619
545
|
info('Checking Claude authentication...');
|
|
620
546
|
|
|
547
|
+
// Get correct Claude command for platform
|
|
548
|
+
const claudeCmd = getClaudeCommand();
|
|
549
|
+
const cmdParts = claudeCmd.split(' ');
|
|
550
|
+
const command = cmdParts[0];
|
|
551
|
+
const args = [...cmdParts.slice(1), 'auth', 'status'];
|
|
552
|
+
|
|
621
553
|
// Use spawn to not block, but with stdio: 'ignore' like the original
|
|
622
554
|
const authPromise = new Promise((resolve, reject) => {
|
|
623
|
-
const child = spawn(
|
|
555
|
+
const child = spawn(command, args, {
|
|
624
556
|
stdio: 'ignore', // Igual que el original
|
|
625
557
|
detached: false,
|
|
626
558
|
windowsHide: true
|
|
@@ -736,20 +668,20 @@ function configureGit() {
|
|
|
736
668
|
info('Configuring Git...');
|
|
737
669
|
|
|
738
670
|
try {
|
|
739
|
-
// Configure line endings
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
try {
|
|
745
|
-
execSync('powershell.exe -Command "git config core.autocrlf true"', { stdio: 'ignore' });
|
|
671
|
+
// Configure line endings based on platform
|
|
672
|
+
// Why: CRLF/LF handling differs between Windows and Unix
|
|
673
|
+
if (isWindows()) {
|
|
674
|
+
// On Windows: Keep CRLF in working directory, convert to LF in repo
|
|
675
|
+
execSync('git config core.autocrlf true', { stdio: 'ignore' });
|
|
746
676
|
success('Line endings configured for Windows (core.autocrlf = true)');
|
|
747
|
-
}
|
|
748
|
-
|
|
677
|
+
} else {
|
|
678
|
+
// On Unix: Keep LF everywhere, convert CRLF to LF on commit
|
|
679
|
+
execSync('git config core.autocrlf input', { stdio: 'ignore' });
|
|
680
|
+
success('Line endings configured for Unix (core.autocrlf = input)');
|
|
749
681
|
}
|
|
750
682
|
|
|
751
683
|
} catch (e) {
|
|
752
|
-
warning('Error configuring Git');
|
|
684
|
+
warning('Error configuring Git: ' + e.message);
|
|
753
685
|
}
|
|
754
686
|
}
|
|
755
687
|
|
|
@@ -822,7 +754,7 @@ function disable(hookName) {
|
|
|
822
754
|
}
|
|
823
755
|
|
|
824
756
|
// Analyze-diff command
|
|
825
|
-
function analyzeDiff(args) {
|
|
757
|
+
async function analyzeDiff(args) {
|
|
826
758
|
if (!checkGitRepo()) {
|
|
827
759
|
error('You are not in a Git repository.');
|
|
828
760
|
return;
|
|
@@ -930,10 +862,6 @@ function analyzeDiff(args) {
|
|
|
930
862
|
return;
|
|
931
863
|
}
|
|
932
864
|
|
|
933
|
-
// Create the prompt for Claude
|
|
934
|
-
const tempDir = `/tmp/claude-analyze-${Date.now()}`;
|
|
935
|
-
fs.mkdirSync(tempDir, { recursive: true });
|
|
936
|
-
|
|
937
865
|
// Check if subagents should be used
|
|
938
866
|
const useSubagents = process.env.CLAUDE_USE_SUBAGENTS === 'true';
|
|
939
867
|
const subagentModel = process.env.CLAUDE_SUBAGENT_MODEL || 'haiku';
|
|
@@ -946,14 +874,13 @@ function analyzeDiff(args) {
|
|
|
946
874
|
? `\n\nIMPORTANT PARALLEL PROCESSING: If analyzing 3+ files, process them in batches of ${subagentBatchSize}. For EACH batch, create that many subagents in parallel using Task tool (send single message with multiple Task calls). Each subagent analyzes one file and provides insights. After ALL batches complete, consolidate into SINGLE JSON with ONE cohesive PR title/description. Model: ${subagentModel}. Example: 4 files with BATCH_SIZE=1 → 4 sequential batches of 1 subagent each. Example: 4 files with BATCH_SIZE=3 → batch 1 has 3 parallel subagents (files 1-3), batch 2 has 1 subagent (file 4).\n`
|
|
947
875
|
: '';
|
|
948
876
|
|
|
949
|
-
const promptFile = path.join(tempDir, 'prompt.txt');
|
|
950
877
|
const prompt = `Analyze the following changes. CONTEXT: ${contextDescription}
|
|
951
878
|
${subagentInstruction}
|
|
952
879
|
Please generate:
|
|
953
880
|
1. A concise and descriptive PR title (maximum 72 characters)
|
|
954
881
|
2. A detailed PR description that includes:
|
|
955
882
|
- Summary of changes
|
|
956
|
-
- Motivation/context
|
|
883
|
+
- Motivation/context
|
|
957
884
|
- Type of change (feature/fix/refactor/docs/etc)
|
|
958
885
|
- Recommended testing
|
|
959
886
|
3. A suggested branch name following the format: type/short-description (example: feature/add-user-auth, fix/memory-leak)
|
|
@@ -979,30 +906,15 @@ ${diffFiles}
|
|
|
979
906
|
=== FULL DIFF ===
|
|
980
907
|
${fullDiff.substring(0, 50000)} ${fullDiff.length > 50000 ? '\n... (truncated diff)' : ''}`;
|
|
981
908
|
|
|
982
|
-
fs.writeFileSync(promptFile, prompt);
|
|
983
|
-
|
|
984
909
|
info('Sending to Claude for analysis...');
|
|
985
910
|
const startTime = Date.now();
|
|
986
911
|
|
|
987
912
|
try {
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
// Extraer el JSON de la respuesta
|
|
991
|
-
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
|
992
|
-
if (!jsonMatch) {
|
|
993
|
-
error('Did not receive a valid JSON response from Claude.');
|
|
994
|
-
console.log('Complete response:', response);
|
|
995
|
-
return;
|
|
996
|
-
}
|
|
913
|
+
// Use cross-platform executeClaude from claude-client.js
|
|
914
|
+
const response = await executeClaude(prompt, { timeout: 180000 }); // 3 minutes for diff analysis
|
|
997
915
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
result = JSON.parse(jsonMatch[0]);
|
|
1001
|
-
} catch (e) {
|
|
1002
|
-
error('Error parsing JSON response: ' + e.message);
|
|
1003
|
-
console.log('JSON received:', jsonMatch[0]);
|
|
1004
|
-
return;
|
|
1005
|
-
}
|
|
916
|
+
// Extract JSON from response using claude-client utility
|
|
917
|
+
const result = extractJSON(response);
|
|
1006
918
|
|
|
1007
919
|
// Show the results
|
|
1008
920
|
console.log('');
|
|
@@ -1080,9 +992,6 @@ ${fullDiff.substring(0, 50000)} ${fullDiff.length > 50000 ? '\n... (truncated di
|
|
|
1080
992
|
|
|
1081
993
|
} catch (e) {
|
|
1082
994
|
error('Error executing Claude: ' + e.message);
|
|
1083
|
-
} finally {
|
|
1084
|
-
// Clean temporary files
|
|
1085
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
1086
995
|
}
|
|
1087
996
|
}
|
|
1088
997
|
|
|
@@ -1192,7 +1101,7 @@ async function update() {
|
|
|
1192
1101
|
info('Checking latest available version...');
|
|
1193
1102
|
|
|
1194
1103
|
try {
|
|
1195
|
-
const currentVersion =
|
|
1104
|
+
const currentVersion = getPackageJson().version;
|
|
1196
1105
|
const latestVersion = await getLatestVersion('claude-git-hooks');
|
|
1197
1106
|
|
|
1198
1107
|
const comparison = compareVersions(currentVersion, latestVersion);
|
|
@@ -1327,7 +1236,7 @@ async function main() {
|
|
|
1327
1236
|
status();
|
|
1328
1237
|
break;
|
|
1329
1238
|
case 'analyze-diff':
|
|
1330
|
-
analyzeDiff(args.slice(1));
|
|
1239
|
+
await analyzeDiff(args.slice(1));
|
|
1331
1240
|
break;
|
|
1332
1241
|
case 'help':
|
|
1333
1242
|
case '--help':
|