claude-git-hooks 2.9.1 → 2.10.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 +107 -0
- package/README.md +209 -755
- package/bin/claude-hooks +97 -2310
- package/lib/commands/analyze-diff.js +262 -0
- package/lib/commands/create-pr.js +374 -0
- package/lib/commands/debug.js +52 -0
- package/lib/commands/help.js +147 -0
- package/lib/commands/helpers.js +389 -0
- package/lib/commands/hooks.js +150 -0
- package/lib/commands/install.js +688 -0
- package/lib/commands/migrate-config.js +103 -0
- package/lib/commands/presets.js +101 -0
- package/lib/commands/setup-github.js +93 -0
- package/lib/commands/telemetry-cmd.js +48 -0
- package/lib/commands/update.js +67 -0
- package/lib/utils/github-api.js +87 -17
- package/lib/utils/github-client.js +9 -550
- package/package.json +1 -1
- package/lib/utils/mcp-setup.js +0 -342
package/lib/utils/mcp-setup.js
DELETED
|
@@ -1,342 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* File: mcp-setup.js
|
|
3
|
-
* Purpose: Automated GitHub MCP setup for Claude CLI
|
|
4
|
-
*
|
|
5
|
-
* Features:
|
|
6
|
-
* - Auto-detect existing configuration
|
|
7
|
-
* - Read token from Claude Desktop config
|
|
8
|
-
* - Interactive token prompt if needed
|
|
9
|
-
* - Configure Claude CLI MCP
|
|
10
|
-
* - Set environment variables
|
|
11
|
-
* - Verify configuration
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import { execSync } from 'child_process';
|
|
15
|
-
import fs from 'fs';
|
|
16
|
-
import path from 'path';
|
|
17
|
-
import os from 'os';
|
|
18
|
-
import logger from './logger.js';
|
|
19
|
-
import { promptConfirmation, promptEditField, showSuccess, showError, showInfo, showWarning } from './interactive-ui.js';
|
|
20
|
-
import { getClaudeCommand } from './claude-client.js';
|
|
21
|
-
import { approveGitHubMcpPermissions, executeMcpCommand } from './github-client.js';
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Check if GitHub MCP is already configured in Claude CLI
|
|
25
|
-
* Why: Avoid duplicate configuration
|
|
26
|
-
*
|
|
27
|
-
* @returns {boolean} - True if configured
|
|
28
|
-
*/
|
|
29
|
-
export const isGitHubMCPConfigured = () => {
|
|
30
|
-
try {
|
|
31
|
-
const { command, args } = getClaudeCommand();
|
|
32
|
-
const fullCommand = `${command} ${args.join(' ')} mcp list`;
|
|
33
|
-
const mcpList = execSync(fullCommand, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] });
|
|
34
|
-
return mcpList.toLowerCase().includes('github');
|
|
35
|
-
} catch (error) {
|
|
36
|
-
logger.debug('mcp-setup - isGitHubMCPConfigured', 'Failed to check MCP list', { error: error.message });
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Find GitHub token in Claude Desktop config
|
|
43
|
-
* Why: Reuse existing token instead of asking user
|
|
44
|
-
*
|
|
45
|
-
* @returns {Object|null} - { token, configPath } or null if not found
|
|
46
|
-
*/
|
|
47
|
-
export const findGitHubTokenInDesktopConfig = () => {
|
|
48
|
-
const possibleConfigPaths = [
|
|
49
|
-
// Linux/macOS standard path
|
|
50
|
-
path.join(os.homedir(), '.config', 'Claude', 'claude_desktop_config.json'),
|
|
51
|
-
// Windows native path
|
|
52
|
-
path.join(os.homedir(), 'AppData', 'Roaming', 'Claude', 'claude_desktop_config.json'),
|
|
53
|
-
// WSL accessing Windows path - try multiple user names
|
|
54
|
-
'/mnt/c/Users/' + os.userInfo().username + '/AppData/Roaming/Claude/claude_desktop_config.json',
|
|
55
|
-
];
|
|
56
|
-
|
|
57
|
-
// Add additional Windows paths by checking if we're in WSL
|
|
58
|
-
if (process.platform === 'linux' && fs.existsSync('/mnt/c')) {
|
|
59
|
-
// We're in WSL, try to find all Windows user directories
|
|
60
|
-
try {
|
|
61
|
-
const usersDir = '/mnt/c/Users';
|
|
62
|
-
if (fs.existsSync(usersDir)) {
|
|
63
|
-
const users = fs.readdirSync(usersDir);
|
|
64
|
-
for (const user of users) {
|
|
65
|
-
const configPath = `/mnt/c/Users/${user}/AppData/Roaming/Claude/claude_desktop_config.json`;
|
|
66
|
-
if (!possibleConfigPaths.includes(configPath)) {
|
|
67
|
-
possibleConfigPaths.push(configPath);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
} catch (error) {
|
|
72
|
-
logger.debug('mcp-setup - findGitHubTokenInDesktopConfig', 'Failed to scan /mnt/c/Users', {
|
|
73
|
-
error: error.message
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
for (const configPath of possibleConfigPaths) {
|
|
79
|
-
try {
|
|
80
|
-
if (fs.existsSync(configPath)) {
|
|
81
|
-
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
82
|
-
const token = config.mcpServers?.github?.env?.GITHUB_PERSONAL_ACCESS_TOKEN;
|
|
83
|
-
|
|
84
|
-
if (token) {
|
|
85
|
-
logger.debug('mcp-setup - findGitHubTokenInDesktopConfig', 'Found token', { configPath });
|
|
86
|
-
return { token, configPath };
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
} catch (error) {
|
|
90
|
-
logger.debug('mcp-setup - findGitHubTokenInDesktopConfig', 'Failed to read config', {
|
|
91
|
-
configPath,
|
|
92
|
-
error: error.message
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return null;
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Add GitHub MCP to Claude CLI
|
|
102
|
-
* Why: Configure MCP server for PR creation
|
|
103
|
-
*
|
|
104
|
-
* @param {boolean} replace - Replace existing configuration
|
|
105
|
-
* @returns {Promise<boolean>} - True if successful
|
|
106
|
-
*/
|
|
107
|
-
export const addGitHubMCP = async (replace = false) => {
|
|
108
|
-
try {
|
|
109
|
-
const { command, args } = getClaudeCommand();
|
|
110
|
-
|
|
111
|
-
// Remove existing if replacing
|
|
112
|
-
if (replace) {
|
|
113
|
-
try {
|
|
114
|
-
const removeCmd = `${command} ${args.join(' ')} mcp remove github`;
|
|
115
|
-
execSync(removeCmd, { stdio: 'ignore' });
|
|
116
|
-
logger.debug('mcp-setup - addGitHubMCP', 'Removed existing GitHub MCP');
|
|
117
|
-
} catch (error) {
|
|
118
|
-
// Ignore errors, may not have remove command
|
|
119
|
-
logger.debug('mcp-setup - addGitHubMCP', 'Failed to remove (may not exist)', { error: error.message });
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Add GitHub MCP
|
|
124
|
-
// Use -- to separate claude options from npx arguments
|
|
125
|
-
const mcpCommand = `${command} ${args.join(' ')} mcp add github npx -- -y @modelcontextprotocol/server-github`;
|
|
126
|
-
logger.debug('mcp-setup - addGitHubMCP', 'Running MCP add command', { mcpCommand });
|
|
127
|
-
|
|
128
|
-
execSync(mcpCommand, { stdio: 'inherit' });
|
|
129
|
-
|
|
130
|
-
logger.debug('mcp-setup - addGitHubMCP', 'Successfully added GitHub MCP');
|
|
131
|
-
return true;
|
|
132
|
-
|
|
133
|
-
} catch (error) {
|
|
134
|
-
logger.error('mcp-setup - addGitHubMCP', 'Failed to add GitHub MCP', error);
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Set environment variable in shell RC files
|
|
141
|
-
* Why: Persist GitHub token across sessions
|
|
142
|
-
*
|
|
143
|
-
* @param {string} token - GitHub Personal Access Token
|
|
144
|
-
* @returns {boolean} - True if set in at least one file
|
|
145
|
-
*/
|
|
146
|
-
export const setEnvironmentVariable = (token) => {
|
|
147
|
-
const envVarLine = `export GITHUB_PERSONAL_ACCESS_TOKEN="${token}"`;
|
|
148
|
-
const shellRcFiles = [
|
|
149
|
-
path.join(os.homedir(), '.bashrc'),
|
|
150
|
-
path.join(os.homedir(), '.bash_profile'),
|
|
151
|
-
path.join(os.homedir(), '.zshrc')
|
|
152
|
-
];
|
|
153
|
-
|
|
154
|
-
let envVarSet = false;
|
|
155
|
-
|
|
156
|
-
for (const rcFile of shellRcFiles) {
|
|
157
|
-
try {
|
|
158
|
-
if (fs.existsSync(rcFile)) {
|
|
159
|
-
const content = fs.readFileSync(rcFile, 'utf8');
|
|
160
|
-
|
|
161
|
-
// Check if already present
|
|
162
|
-
if (content.includes('GITHUB_PERSONAL_ACCESS_TOKEN')) {
|
|
163
|
-
logger.debug('mcp-setup - setEnvironmentVariable', 'Already present', { rcFile });
|
|
164
|
-
showInfo(`Environment variable already in ${path.basename(rcFile)}`);
|
|
165
|
-
envVarSet = true;
|
|
166
|
-
continue;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Add to file
|
|
170
|
-
fs.appendFileSync(rcFile, `\n# GitHub MCP token for Claude CLI\n${envVarLine}\n`);
|
|
171
|
-
showSuccess(`Added environment variable to ${path.basename(rcFile)}`);
|
|
172
|
-
logger.debug('mcp-setup - setEnvironmentVariable', 'Added to file', { rcFile });
|
|
173
|
-
envVarSet = true;
|
|
174
|
-
}
|
|
175
|
-
} catch (error) {
|
|
176
|
-
logger.debug('mcp-setup - setEnvironmentVariable', 'Failed to update file', {
|
|
177
|
-
rcFile,
|
|
178
|
-
error: error.message
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (!envVarSet) {
|
|
184
|
-
showWarning('Could not find shell RC file (.bashrc, .bash_profile, .zshrc)');
|
|
185
|
-
console.log('');
|
|
186
|
-
console.log('Please add this line to your shell configuration manually:');
|
|
187
|
-
console.log(` ${envVarLine}`);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Set for current session
|
|
191
|
-
process.env.GITHUB_PERSONAL_ACCESS_TOKEN = token;
|
|
192
|
-
|
|
193
|
-
return envVarSet;
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Setup GitHub MCP for Claude CLI
|
|
198
|
-
* Why: Automate MCP configuration to enable create-pr functionality
|
|
199
|
-
*
|
|
200
|
-
* Interactive setup process:
|
|
201
|
-
* 1. Check if GitHub MCP already configured
|
|
202
|
-
* 2. Try to read GitHub token from Claude Desktop config
|
|
203
|
-
* 3. If not found, prompt user for token
|
|
204
|
-
* 4. Run: claude mcp add github npx -y @modelcontextprotocol/server-github
|
|
205
|
-
* 5. Configure environment variable for token
|
|
206
|
-
* 6. Verify configuration
|
|
207
|
-
*
|
|
208
|
-
* @returns {Promise<void>}
|
|
209
|
-
*/
|
|
210
|
-
export const setupGitHubMCP = async () => {
|
|
211
|
-
try {
|
|
212
|
-
console.log('');
|
|
213
|
-
showInfo('GitHub MCP Setup for Claude CLI');
|
|
214
|
-
console.log('');
|
|
215
|
-
|
|
216
|
-
// Step 1: Check if already configured
|
|
217
|
-
console.log('🔍 Checking current MCP configuration...');
|
|
218
|
-
|
|
219
|
-
let mcpList = '';
|
|
220
|
-
try {
|
|
221
|
-
const { command, args } = getClaudeCommand();
|
|
222
|
-
const fullCommand = `${command} ${args.join(' ')} mcp list`;
|
|
223
|
-
mcpList = execSync(fullCommand, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] });
|
|
224
|
-
} catch (error) {
|
|
225
|
-
showError('Failed to run "claude mcp list". Is Claude CLI installed?');
|
|
226
|
-
console.error('Make sure Claude CLI is installed: npm install -g @anthropic-ai/claude-cli');
|
|
227
|
-
console.error('Error:', error.message);
|
|
228
|
-
process.exit(1);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const hasGitHub = isGitHubMCPConfigured();
|
|
232
|
-
if (hasGitHub) {
|
|
233
|
-
showSuccess('GitHub MCP is already configured!');
|
|
234
|
-
console.log('');
|
|
235
|
-
console.log(mcpList);
|
|
236
|
-
|
|
237
|
-
const reconfigure = await promptConfirmation('Do you want to reconfigure it?', false);
|
|
238
|
-
if (!reconfigure) {
|
|
239
|
-
showInfo('Setup cancelled. Your existing configuration is unchanged.');
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Step 2: Try to read token from Claude Desktop config
|
|
245
|
-
console.log('');
|
|
246
|
-
console.log('🔑 Looking for GitHub token...');
|
|
247
|
-
|
|
248
|
-
let githubToken = null;
|
|
249
|
-
const tokenInfo = findGitHubTokenInDesktopConfig();
|
|
250
|
-
|
|
251
|
-
if (tokenInfo) {
|
|
252
|
-
githubToken = tokenInfo.token;
|
|
253
|
-
showSuccess('Found GitHub token in Claude Desktop config');
|
|
254
|
-
console.log(` Location: ${tokenInfo.configPath}`);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Step 3: If not found, prompt user
|
|
258
|
-
if (!githubToken) {
|
|
259
|
-
showWarning('No GitHub token found in Claude Desktop config');
|
|
260
|
-
console.log('');
|
|
261
|
-
console.log('You need a GitHub Personal Access Token with these permissions:');
|
|
262
|
-
console.log(' - repo (Full control of private repositories)');
|
|
263
|
-
console.log(' - read:org (Read org and team membership)');
|
|
264
|
-
console.log('');
|
|
265
|
-
console.log('Create one at: https://github.com/settings/tokens/new');
|
|
266
|
-
console.log('');
|
|
267
|
-
|
|
268
|
-
githubToken = await promptEditField('GitHub Personal Access Token', '');
|
|
269
|
-
|
|
270
|
-
if (!githubToken || githubToken.trim() === '') {
|
|
271
|
-
showError('GitHub token is required. Setup cancelled.');
|
|
272
|
-
process.exit(1);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Step 4: Add GitHub MCP to Claude CLI
|
|
277
|
-
console.log('');
|
|
278
|
-
console.log('⚙️ Configuring GitHub MCP for Claude CLI...');
|
|
279
|
-
|
|
280
|
-
const added = await addGitHubMCP(hasGitHub);
|
|
281
|
-
if (!added) {
|
|
282
|
-
showError('Failed to add GitHub MCP');
|
|
283
|
-
process.exit(1);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
showSuccess('GitHub MCP added to Claude CLI');
|
|
287
|
-
|
|
288
|
-
// Step 5: Configure environment variable
|
|
289
|
-
console.log('');
|
|
290
|
-
console.log('🔧 Setting up environment variable...');
|
|
291
|
-
|
|
292
|
-
setEnvironmentVariable(githubToken);
|
|
293
|
-
|
|
294
|
-
// Step 6: Approve MCP permissions
|
|
295
|
-
console.log('');
|
|
296
|
-
console.log('🔐 Approving MCP permissions...');
|
|
297
|
-
|
|
298
|
-
const permResult = await approveGitHubMcpPermissions();
|
|
299
|
-
if (permResult.success) {
|
|
300
|
-
showSuccess('MCP permissions approved');
|
|
301
|
-
} else {
|
|
302
|
-
showWarning('Some permissions may need manual approval');
|
|
303
|
-
console.log(' Run: claude mcp approve github --all');
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Step 7: Verify configuration
|
|
307
|
-
console.log('');
|
|
308
|
-
console.log('✅ Verifying configuration...');
|
|
309
|
-
|
|
310
|
-
try {
|
|
311
|
-
const { command, args } = getClaudeCommand();
|
|
312
|
-
const fullCommand = `${command} ${args.join(' ')} mcp list`;
|
|
313
|
-
const verifyList = execSync(fullCommand, { encoding: 'utf8' });
|
|
314
|
-
if (verifyList.toLowerCase().includes('github')) {
|
|
315
|
-
showSuccess('GitHub MCP is configured and ready!');
|
|
316
|
-
console.log('');
|
|
317
|
-
console.log(verifyList);
|
|
318
|
-
} else {
|
|
319
|
-
showWarning('Configuration completed but GitHub MCP not showing in list');
|
|
320
|
-
console.log('You may need to restart your terminal');
|
|
321
|
-
}
|
|
322
|
-
} catch (error) {
|
|
323
|
-
showWarning('Could not verify configuration');
|
|
324
|
-
logger.debug('mcp-setup - setupGitHubMCP', 'Verification failed', { error: error.message });
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Final instructions
|
|
328
|
-
console.log('');
|
|
329
|
-
showSuccess('Setup complete!');
|
|
330
|
-
console.log('');
|
|
331
|
-
console.log('Next steps:');
|
|
332
|
-
console.log(' 1. Restart your terminal (or run: source ~/.bashrc)');
|
|
333
|
-
console.log(' 2. Verify with: claude mcp list');
|
|
334
|
-
console.log(' 3. Try creating a PR: claude-hooks create-pr develop');
|
|
335
|
-
console.log('');
|
|
336
|
-
|
|
337
|
-
} catch (error) {
|
|
338
|
-
showError('Error during MCP setup: ' + error.message);
|
|
339
|
-
console.error(error);
|
|
340
|
-
throw error;
|
|
341
|
-
}
|
|
342
|
-
};
|