claude-git-hooks 2.7.1 → 2.8.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 +113 -0
- package/README.md +65 -51
- package/bin/claude-hooks +306 -25
- package/lib/config.js +176 -83
- package/lib/hooks/prepare-commit-msg.js +2 -3
- package/lib/utils/claude-client.js +153 -59
- package/lib/utils/claude-diagnostics.js +50 -6
- package/package.json +1 -1
- package/templates/config.advanced.example.json +113 -0
- package/templates/config.example.json +53 -36
- package/templates/presets/ai/config.json +5 -12
- package/templates/presets/backend/config.json +5 -12
- package/templates/presets/database/config.json +5 -12
- package/templates/presets/default/config.json +5 -12
- package/templates/presets/frontend/config.json +5 -12
- package/templates/presets/fullstack/config.json +5 -12
package/bin/claude-hooks
CHANGED
|
@@ -8,7 +8,7 @@ import readline from 'readline';
|
|
|
8
8
|
import https from 'https';
|
|
9
9
|
import { fileURLToPath } from 'url';
|
|
10
10
|
import { dirname } from 'path';
|
|
11
|
-
import { executeClaude, extractJSON } from '../lib/utils/claude-client.js';
|
|
11
|
+
import { executeClaude, executeClaudeWithRetry, extractJSON, analyzeCode } from '../lib/utils/claude-client.js';
|
|
12
12
|
import { loadPrompt } from '../lib/utils/prompt-builder.js';
|
|
13
13
|
import { listPresets } from '../lib/utils/preset-loader.js';
|
|
14
14
|
import { getConfig } from '../lib/config.js';
|
|
@@ -398,28 +398,64 @@ async function install(args) {
|
|
|
398
398
|
}
|
|
399
399
|
});
|
|
400
400
|
|
|
401
|
-
//
|
|
401
|
+
// Create .claude/prompts directory for markdown templates
|
|
402
|
+
const promptsDir = path.join(claudeDir, 'prompts');
|
|
403
|
+
if (!fs.existsSync(promptsDir)) {
|
|
404
|
+
fs.mkdirSync(promptsDir, { recursive: true });
|
|
405
|
+
success('.claude/prompts directory created');
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Copy template files (.md and .json) to appropriate locations
|
|
402
409
|
const templateFiles = fs.readdirSync(templatesPath)
|
|
403
410
|
.filter(file => {
|
|
404
411
|
const filePath = path.join(templatesPath, file);
|
|
405
|
-
|
|
412
|
+
// Exclude example.json files and only include .md and .json files
|
|
413
|
+
return fs.statSync(filePath).isFile() &&
|
|
414
|
+
(file.endsWith('.md') || file.endsWith('.json')) &&
|
|
415
|
+
!file.includes('example.json');
|
|
406
416
|
});
|
|
407
417
|
|
|
408
418
|
templateFiles.forEach(file => {
|
|
409
419
|
const sourcePath = path.join(templatesPath, file);
|
|
410
|
-
|
|
420
|
+
let destPath;
|
|
421
|
+
let destLocation;
|
|
422
|
+
|
|
423
|
+
// .md files go to .claude/prompts/, .json files go to .claude/
|
|
424
|
+
if (file.endsWith('.md')) {
|
|
425
|
+
destPath = path.join(promptsDir, file);
|
|
426
|
+
destLocation = '.claude/prompts/';
|
|
427
|
+
} else {
|
|
428
|
+
destPath = path.join(claudeDir, file);
|
|
429
|
+
destLocation = '.claude/';
|
|
430
|
+
}
|
|
411
431
|
|
|
412
432
|
// In force mode or if it doesn't exist, copy the file
|
|
413
433
|
if (isForce || !fs.existsSync(destPath)) {
|
|
414
434
|
if (fs.existsSync(sourcePath)) {
|
|
415
435
|
fs.copyFileSync(sourcePath, destPath);
|
|
416
|
-
success(`${file} installed in
|
|
436
|
+
success(`${file} installed in ${destLocation}`);
|
|
417
437
|
}
|
|
418
438
|
} else {
|
|
419
439
|
info(`${file} already exists (skipped)`);
|
|
420
440
|
}
|
|
421
441
|
});
|
|
422
442
|
|
|
443
|
+
// Clean up old .md files from .claude/ root (v2.8.0 migration)
|
|
444
|
+
// .md files should now be in .claude/prompts/, not .claude/
|
|
445
|
+
const oldMdFiles = fs.readdirSync(claudeDir)
|
|
446
|
+
.filter(file => {
|
|
447
|
+
const filePath = path.join(claudeDir, file);
|
|
448
|
+
return fs.statSync(filePath).isFile() && file.endsWith('.md');
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
if (oldMdFiles.length > 0) {
|
|
452
|
+
oldMdFiles.forEach(file => {
|
|
453
|
+
const oldPath = path.join(claudeDir, file);
|
|
454
|
+
fs.unlinkSync(oldPath);
|
|
455
|
+
info(`Removed old template from .claude/: ${file} (now in prompts/)`);
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
|
|
423
459
|
// Copy presets directory structure
|
|
424
460
|
const presetsSourcePath = path.join(templatesPath, 'presets');
|
|
425
461
|
const presetsDestPath = path.join(claudeDir, 'presets');
|
|
@@ -460,15 +496,74 @@ async function install(args) {
|
|
|
460
496
|
success(`${presetDirs.length} presets installed in .claude/presets/`);
|
|
461
497
|
}
|
|
462
498
|
|
|
463
|
-
// Special handling for config.json
|
|
464
|
-
const configExamplePath = path.join(claudeDir, 'config.example.json');
|
|
499
|
+
// Special handling for config.json (v2.8.0+): backup old, create new simplified
|
|
465
500
|
const configPath = path.join(claudeDir, 'config.json');
|
|
501
|
+
const configOldDir = path.join(claudeDir, 'config_old');
|
|
502
|
+
const configExampleDir = path.join(claudeDir, 'config_example');
|
|
503
|
+
|
|
504
|
+
// Create config_old directory if needed
|
|
505
|
+
if (!fs.existsSync(configOldDir)) {
|
|
506
|
+
fs.mkdirSync(configOldDir, { recursive: true });
|
|
507
|
+
}
|
|
466
508
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
}
|
|
471
|
-
|
|
509
|
+
// Create config_example directory
|
|
510
|
+
if (!fs.existsSync(configExampleDir)) {
|
|
511
|
+
fs.mkdirSync(configExampleDir, { recursive: true });
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// Copy example configs to config_example/ directly from templates/
|
|
515
|
+
const exampleConfigs = ['config.example.json', 'config.advanced.example.json'];
|
|
516
|
+
exampleConfigs.forEach(exampleFile => {
|
|
517
|
+
const sourcePath = path.join(templatesPath, exampleFile);
|
|
518
|
+
const destPath = path.join(configExampleDir, exampleFile);
|
|
519
|
+
if (fs.existsSync(sourcePath)) {
|
|
520
|
+
fs.copyFileSync(sourcePath, destPath);
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
success('Example configs installed in .claude/config_example/');
|
|
524
|
+
|
|
525
|
+
// Backup existing config if it exists (legacy format migration)
|
|
526
|
+
let needsMigration = false;
|
|
527
|
+
if (fs.existsSync(configPath)) {
|
|
528
|
+
const backupPath = path.join(configOldDir, `config.json.${Date.now()}`);
|
|
529
|
+
fs.copyFileSync(configPath, backupPath);
|
|
530
|
+
info(`Existing config backed up: ${backupPath}`);
|
|
531
|
+
|
|
532
|
+
// Read old config to check if it's legacy format
|
|
533
|
+
const oldConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
534
|
+
if (!oldConfig.version || oldConfig.version !== '2.8.0') {
|
|
535
|
+
warning('Legacy config detected - will be replaced with v2.8.0 format');
|
|
536
|
+
needsMigration = true;
|
|
537
|
+
|
|
538
|
+
// Delete old config to force new format
|
|
539
|
+
fs.unlinkSync(configPath);
|
|
540
|
+
} else {
|
|
541
|
+
info('Config already in v2.8.0 format - keeping existing file');
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Create new config.json from minimal example if it doesn't exist
|
|
546
|
+
if (!fs.existsSync(configPath)) {
|
|
547
|
+
// Read example and extract minimal config
|
|
548
|
+
const examplePath = path.join(configExampleDir, 'config.example.json');
|
|
549
|
+
const exampleContent = fs.readFileSync(examplePath, 'utf8');
|
|
550
|
+
const exampleJson = JSON.parse(exampleContent);
|
|
551
|
+
|
|
552
|
+
// Create minimal config: just version and preset
|
|
553
|
+
const minimalConfig = {
|
|
554
|
+
version: exampleJson.version,
|
|
555
|
+
preset: exampleJson.preset
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
fs.writeFileSync(configPath, JSON.stringify(minimalConfig, null, 4));
|
|
559
|
+
success('config.json created with minimal v2.8.0 format');
|
|
560
|
+
info('📝 Customize: .claude/config.json (see config_example/ for examples)');
|
|
561
|
+
|
|
562
|
+
// Auto-run migration if needed to preserve settings
|
|
563
|
+
if (needsMigration) {
|
|
564
|
+
info('🔄 Auto-migrating settings from backup...');
|
|
565
|
+
await autoMigrateConfig(configPath, path.join(configOldDir, fs.readdirSync(configOldDir).sort().pop()));
|
|
566
|
+
}
|
|
472
567
|
}
|
|
473
568
|
|
|
474
569
|
// Create settings.local.json for sensitive data (gitignored)
|
|
@@ -493,21 +588,31 @@ async function install(args) {
|
|
|
493
588
|
console.log(' git commit -m "auto" # Generate message automatically');
|
|
494
589
|
console.log(' git commit -m "message" # Analyze code before commit');
|
|
495
590
|
console.log(' git commit --no-verify # Skip analysis completely');
|
|
496
|
-
console.log('\n💡 Configuration:');
|
|
591
|
+
console.log('\n💡 Configuration (v2.8.0):');
|
|
497
592
|
console.log(' 📁 All templates installed in .claude/');
|
|
498
|
-
console.log(' 📝 Edit .claude/config.json
|
|
499
|
-
console.log('
|
|
500
|
-
console.log('
|
|
501
|
-
console.log('
|
|
593
|
+
console.log(' 📝 Edit .claude/config.json (minimal by default)');
|
|
594
|
+
console.log(' 📂 Examples: .claude/config_example/');
|
|
595
|
+
console.log(' 📦 Backups: .claude/config_old/');
|
|
596
|
+
console.log(' 🎯 Presets: backend, frontend, fullstack, database, ai, default');
|
|
597
|
+
console.log(' 🚀 Parallel analysis enabled by default (hardcoded)');
|
|
598
|
+
console.log(' 🐛 Debug mode: claude-hooks --debug true');
|
|
502
599
|
console.log('\n🔗 GitHub PR Creation (v2.5.0+):');
|
|
503
|
-
console.log(' claude-hooks setup-github # Configure GitHub token
|
|
504
|
-
console.log(' claude-hooks create-pr main # Create PR with auto-
|
|
505
|
-
console.log('\n📖
|
|
600
|
+
console.log(' claude-hooks setup-github # Configure GitHub token');
|
|
601
|
+
console.log(' claude-hooks create-pr main # Create PR with auto-metadata');
|
|
602
|
+
console.log('\n📖 Minimal config.json (v2.8.0):');
|
|
603
|
+
console.log(' {');
|
|
604
|
+
console.log(' "version": "2.8.0",');
|
|
605
|
+
console.log(' "preset": "backend"');
|
|
606
|
+
console.log(' }');
|
|
607
|
+
console.log('\n📖 With GitHub customization:');
|
|
506
608
|
console.log(' {');
|
|
609
|
+
console.log(' "version": "2.8.0",');
|
|
507
610
|
console.log(' "preset": "backend",');
|
|
508
|
-
console.log(' "
|
|
509
|
-
console.log('
|
|
611
|
+
console.log(' "overrides": {');
|
|
612
|
+
console.log(' "github": { "pr": { "reviewers": ["your-username"] } }');
|
|
613
|
+
console.log(' }');
|
|
510
614
|
console.log(' }');
|
|
615
|
+
console.log('\n🔧 Advanced: see .claude/config_example/config.advanced.example.json');
|
|
511
616
|
console.log('\nFor more options: claude-hooks --help');
|
|
512
617
|
}
|
|
513
618
|
|
|
@@ -968,8 +1073,8 @@ async function analyzeDiff(args) {
|
|
|
968
1073
|
const startTime = Date.now();
|
|
969
1074
|
|
|
970
1075
|
try {
|
|
971
|
-
// Use cross-platform
|
|
972
|
-
const response = await
|
|
1076
|
+
// Use cross-platform executeClaudeWithRetry from claude-client.js
|
|
1077
|
+
const response = await executeClaudeWithRetry(prompt, { timeout: 180000 }); // 3 minutes for diff analysis
|
|
973
1078
|
|
|
974
1079
|
// Extract JSON from response using claude-client utility
|
|
975
1080
|
const result = extractJSON(response);
|
|
@@ -1231,7 +1336,7 @@ async function createPr(args) {
|
|
|
1231
1336
|
|
|
1232
1337
|
showInfo('Generating PR metadata with Claude...');
|
|
1233
1338
|
logger.debug('create-pr', 'Calling Claude with prompt', { promptLength: prompt.length });
|
|
1234
|
-
const response = await
|
|
1339
|
+
const response = await executeClaudeWithRetry(prompt, { timeout: 180000 });
|
|
1235
1340
|
logger.debug('create-pr', 'Claude response received', { responseLength: response.length });
|
|
1236
1341
|
|
|
1237
1342
|
const analysisResult = extractJSON(response);
|
|
@@ -1853,6 +1958,179 @@ async function currentPreset() {
|
|
|
1853
1958
|
}
|
|
1854
1959
|
}
|
|
1855
1960
|
|
|
1961
|
+
// ============================================================================
|
|
1962
|
+
// DEPRECATED CODE SECTION - Will be removed in v3.0.0
|
|
1963
|
+
// ============================================================================
|
|
1964
|
+
// This section contains migration code for legacy configs (pre-v2.8.0)
|
|
1965
|
+
// Auto-executed during install when legacy config detected
|
|
1966
|
+
// Manual command: claude-hooks migrate-config
|
|
1967
|
+
// ============================================================================
|
|
1968
|
+
|
|
1969
|
+
/**
|
|
1970
|
+
* Extracts allowed settings from legacy config format
|
|
1971
|
+
* Shared by both autoMigrateConfig and migrateConfig
|
|
1972
|
+
*
|
|
1973
|
+
* @param {Object} rawConfig - Legacy format config
|
|
1974
|
+
* @returns {Object} Allowed overrides only
|
|
1975
|
+
*/
|
|
1976
|
+
function extractLegacySettings(rawConfig) {
|
|
1977
|
+
const allowedOverrides = {};
|
|
1978
|
+
|
|
1979
|
+
// GitHub PR config (fully allowed)
|
|
1980
|
+
if (rawConfig.github?.pr) {
|
|
1981
|
+
allowedOverrides.github = { pr: {} };
|
|
1982
|
+
if (rawConfig.github.pr.defaultBase !== undefined) {
|
|
1983
|
+
allowedOverrides.github.pr.defaultBase = rawConfig.github.pr.defaultBase;
|
|
1984
|
+
}
|
|
1985
|
+
if (rawConfig.github.pr.reviewers !== undefined) {
|
|
1986
|
+
allowedOverrides.github.pr.reviewers = rawConfig.github.pr.reviewers;
|
|
1987
|
+
}
|
|
1988
|
+
if (rawConfig.github.pr.labelRules !== undefined) {
|
|
1989
|
+
allowedOverrides.github.pr.labelRules = rawConfig.github.pr.labelRules;
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
// Subagent batchSize (allowed)
|
|
1994
|
+
if (rawConfig.subagents?.batchSize !== undefined) {
|
|
1995
|
+
allowedOverrides.subagents = { batchSize: rawConfig.subagents.batchSize };
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
// Advanced params (preserved with warning in manual migration)
|
|
1999
|
+
if (rawConfig.analysis?.ignoreExtensions !== undefined) {
|
|
2000
|
+
if (!allowedOverrides.analysis) allowedOverrides.analysis = {};
|
|
2001
|
+
allowedOverrides.analysis.ignoreExtensions = rawConfig.analysis.ignoreExtensions;
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
if (rawConfig.commitMessage?.taskIdPattern !== undefined) {
|
|
2005
|
+
if (!allowedOverrides.commitMessage) allowedOverrides.commitMessage = {};
|
|
2006
|
+
allowedOverrides.commitMessage.taskIdPattern = rawConfig.commitMessage.taskIdPattern;
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
if (rawConfig.subagents?.model !== undefined) {
|
|
2010
|
+
if (!allowedOverrides.subagents) allowedOverrides.subagents = {};
|
|
2011
|
+
allowedOverrides.subagents.model = rawConfig.subagents.model;
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
return allowedOverrides;
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
/**
|
|
2018
|
+
* Auto-migrates legacy config during installation
|
|
2019
|
+
* Called automatically by installer when legacy format detected
|
|
2020
|
+
*
|
|
2021
|
+
* @param {string} newConfigPath - Path to new config.json
|
|
2022
|
+
* @param {string} backupConfigPath - Path to backup of old config
|
|
2023
|
+
*/
|
|
2024
|
+
async function autoMigrateConfig(newConfigPath, backupConfigPath) {
|
|
2025
|
+
try {
|
|
2026
|
+
const rawConfig = JSON.parse(fs.readFileSync(backupConfigPath, 'utf8'));
|
|
2027
|
+
const allowedOverrides = extractLegacySettings(rawConfig);
|
|
2028
|
+
|
|
2029
|
+
// Read the newly created minimal config
|
|
2030
|
+
const newConfig = JSON.parse(fs.readFileSync(newConfigPath, 'utf8'));
|
|
2031
|
+
|
|
2032
|
+
// Add overrides if any
|
|
2033
|
+
if (Object.keys(allowedOverrides).length > 0) {
|
|
2034
|
+
newConfig.overrides = allowedOverrides;
|
|
2035
|
+
fs.writeFileSync(newConfigPath, JSON.stringify(newConfig, null, 4));
|
|
2036
|
+
success('✅ Settings migrated from legacy config');
|
|
2037
|
+
info(`📋 Preserved ${Object.keys(allowedOverrides).length} custom settings`);
|
|
2038
|
+
}
|
|
2039
|
+
} catch (err) {
|
|
2040
|
+
warning(`⚠️ Could not auto-migrate settings: ${err.message}`);
|
|
2041
|
+
info('💡 Run "claude-hooks migrate-config" manually if needed');
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
/**
|
|
2046
|
+
* Migrates legacy config.json to v2.8.0 format (Manual command)
|
|
2047
|
+
* Why: Simplifies configuration, reduces redundancy
|
|
2048
|
+
*
|
|
2049
|
+
* DEPRECATED: Will be removed in v3.0.0 (most users will have migrated by then)
|
|
2050
|
+
*/
|
|
2051
|
+
async function migrateConfig() {
|
|
2052
|
+
const claudeDir = '.claude';
|
|
2053
|
+
const configPath = path.join(claudeDir, 'config.json');
|
|
2054
|
+
|
|
2055
|
+
if (!fs.existsSync(configPath)) {
|
|
2056
|
+
info('ℹ️ No config file found. Nothing to migrate.');
|
|
2057
|
+
console.log('\n💡 To create a new config:');
|
|
2058
|
+
console.log(' 1. Run: claude-hooks install --force');
|
|
2059
|
+
console.log(' 2. Or copy from: .claude/config_example/config.example.json');
|
|
2060
|
+
return;
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
try {
|
|
2064
|
+
const rawConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
2065
|
+
|
|
2066
|
+
// Check if already in v2.8.0 format
|
|
2067
|
+
if (rawConfig.version === '2.8.0') {
|
|
2068
|
+
success('✅ Config is already in v2.8.0 format.');
|
|
2069
|
+
return;
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
info('📦 Starting config migration to v2.8.0...');
|
|
2073
|
+
|
|
2074
|
+
// Create backup in config_old/
|
|
2075
|
+
const configOldDir = path.join(claudeDir, 'config_old');
|
|
2076
|
+
if (!fs.existsSync(configOldDir)) {
|
|
2077
|
+
fs.mkdirSync(configOldDir, { recursive: true });
|
|
2078
|
+
}
|
|
2079
|
+
const backupPath = path.join(configOldDir, `config.json.${Date.now()}`);
|
|
2080
|
+
fs.copyFileSync(configPath, backupPath);
|
|
2081
|
+
success(`Backup created: ${backupPath}`);
|
|
2082
|
+
|
|
2083
|
+
// Extract only allowed parameters
|
|
2084
|
+
const allowedOverrides = extractLegacySettings(rawConfig);
|
|
2085
|
+
|
|
2086
|
+
// Check for advanced params
|
|
2087
|
+
const hasAdvancedParams = allowedOverrides.analysis?.ignoreExtensions ||
|
|
2088
|
+
allowedOverrides.commitMessage?.taskIdPattern ||
|
|
2089
|
+
allowedOverrides.subagents?.model;
|
|
2090
|
+
|
|
2091
|
+
// Build new config
|
|
2092
|
+
const newConfig = {
|
|
2093
|
+
version: '2.8.0',
|
|
2094
|
+
preset: rawConfig.preset || 'default'
|
|
2095
|
+
};
|
|
2096
|
+
|
|
2097
|
+
// Only add overrides if there are any
|
|
2098
|
+
if (Object.keys(allowedOverrides).length > 0) {
|
|
2099
|
+
newConfig.overrides = allowedOverrides;
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
// Show diff
|
|
2103
|
+
console.log('\n📝 Migration preview:');
|
|
2104
|
+
console.log(` Old format: ${Object.keys(rawConfig).length} top-level keys`);
|
|
2105
|
+
console.log(` New format: ${Object.keys(newConfig).length} top-level keys`);
|
|
2106
|
+
if (Object.keys(allowedOverrides).length > 0) {
|
|
2107
|
+
console.log(` Preserved: ${Object.keys(allowedOverrides).length} override sections`);
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
// Write new config
|
|
2111
|
+
fs.writeFileSync(configPath, JSON.stringify(newConfig, null, 4));
|
|
2112
|
+
success('✅ Config migrated to v2.8.0 successfully!');
|
|
2113
|
+
|
|
2114
|
+
if (hasAdvancedParams) {
|
|
2115
|
+
warning('⚠️ Advanced parameters detected and preserved');
|
|
2116
|
+
info('📖 See .claude/config.advanced.example.json for documentation');
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
console.log(`\n✨ New config:`);
|
|
2120
|
+
console.log(JSON.stringify(newConfig, null, 2));
|
|
2121
|
+
console.log(`\n💾 Old config backed up to: ${backupPath}`);
|
|
2122
|
+
console.log('\n💡 Many parameters are now hardcoded with sensible defaults');
|
|
2123
|
+
console.log(' See CHANGELOG.md for full list of changes');
|
|
2124
|
+
|
|
2125
|
+
} catch (error) {
|
|
2126
|
+
error(`Failed to migrate config: ${error.message}`);
|
|
2127
|
+
console.log('\n💡 Manual migration:');
|
|
2128
|
+
console.log(' 1. Backup your current config');
|
|
2129
|
+
console.log(' 2. See .claude/config.example.json for new format');
|
|
2130
|
+
console.log(' 3. Copy minimal example and customize');
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
|
|
1856
2134
|
/**
|
|
1857
2135
|
* Sets debug mode
|
|
1858
2136
|
* Why: Enables detailed logging for troubleshooting
|
|
@@ -1942,6 +2220,9 @@ async function main() {
|
|
|
1942
2220
|
error(`Unknown preset subcommand: ${args[1]}`);
|
|
1943
2221
|
}
|
|
1944
2222
|
break;
|
|
2223
|
+
case 'migrate-config':
|
|
2224
|
+
await migrateConfig();
|
|
2225
|
+
break;
|
|
1945
2226
|
case '--debug':
|
|
1946
2227
|
await setDebug(args[1]);
|
|
1947
2228
|
break;
|