ccoptimizer
Version:
š Optimize your Claude Code experience by analyzing your conversation patterns
120 lines ⢠5.76 kB
JavaScript
import chalk from 'chalk';
import ora from 'ora';
import { analyzeConversations } from './analyzer.js';
import { generateClaudeMd } from './generator.js';
import { homedir } from 'os';
import { existsSync } from 'fs';
import { join } from 'path';
async function main() {
console.log(chalk.cyan.bold('\nš CC Optimizer - Personalize your Claude experience\n'));
// Handle graceful shutdown
process.on('SIGINT', () => {
console.log(chalk.yellow('\n\nā ļø Analysis cancelled by user'));
process.exit(0);
});
// Quick check for Claude CLI
try {
const { execSync } = await import('child_process');
execSync('which claude', { stdio: 'ignore' });
}
catch {
console.log(chalk.yellow('ā ļø Claude CLI not found. Please install it first:'));
console.log(chalk.gray(' npm install -g @anthropic-ai/claude-code\n'));
process.exit(1);
}
const spinner = ora('Checking Claude projects directory...').start();
try {
const projectsPath = join(homedir(), '.claude', 'projects');
if (!existsSync(projectsPath)) {
spinner.fail('Claude projects directory not found');
console.log(chalk.yellow('Make sure you have used Claude Code at least once'));
process.exit(1);
}
spinner.text = 'Scanning conversation history...';
const startTime = Date.now();
const analysis = await analyzeConversations(projectsPath, spinner);
const duration = Math.round((Date.now() - startTime) / 1000);
spinner.succeed(`Analyzed ${chalk.green(analysis.conversationCount)} conversations in ${chalk.cyan(duration + 's')}`);
if (analysis.insights && analysis.insights.length > 0) {
console.log(chalk.blue('\nš Insights gathered from your conversations'));
}
const outputSpinner = ora('\nš§ Generating optimized CLAUDE.md...').start();
const claudeMdPath = join(homedir(), '.claude', 'CLAUDE.md');
const newContent = await generateClaudeMd(analysis.insights);
// Smart merge with existing CLAUDE.md
const { readFileSync, writeFileSync, copyFileSync } = await import('fs');
let finalContent = newContent;
if (existsSync(claudeMdPath)) {
const backupPath = claudeMdPath + '.backup';
copyFileSync(claudeMdPath, backupPath);
const existingContent = readFileSync(claudeMdPath, 'utf8');
const marker = '## Auto-Generated by ccoptimizer';
if (existingContent.includes(marker)) {
// Replace only the auto-generated section
const markerIndex = existingContent.indexOf(marker);
const beforeMarker = existingContent.substring(0, markerIndex).trimEnd();
finalContent = beforeMarker + '\n\n' + marker + '\n\n' + newContent.replace('# Optimized Claude Instructions\n\n', '');
}
else {
// Append as new section
finalContent = existingContent.trimEnd() + '\n\n' + marker + '\n\n' + newContent.replace('# Optimized Claude Instructions\n\n', '');
}
}
outputSpinner.stop();
if (existsSync(claudeMdPath)) {
console.log(chalk.gray('ā Backed up existing CLAUDE.md'));
}
// Show preview
console.log(chalk.blue('\nš Preview of changes:\n'));
console.log(chalk.gray('ā'.repeat(50)));
// Show just the new/updated section
const markerIndex = finalContent.indexOf('## Auto-Generated by ccoptimizer');
if (markerIndex !== -1) {
const preview = finalContent.substring(markerIndex);
console.log(preview.substring(0, 500) + (preview.length > 500 ? '\n...' : ''));
}
else {
console.log(finalContent.substring(0, 500) + (finalContent.length > 500 ? '\n...' : ''));
}
console.log(chalk.gray('ā'.repeat(50)));
// Check for --yes flag to skip prompt
let shouldApply = process.argv.includes('--yes') || process.argv.includes('-y');
if (!shouldApply) {
// Ask for confirmation
const { createInterface } = await import('readline');
const rl = createInterface({
input: process.stdin,
output: process.stdout
});
const answer = await new Promise(resolve => {
rl.question(chalk.yellow('\nā Apply these changes to CLAUDE.md? [Y/n]: '), (ans) => {
rl.close();
const response = ans.toLowerCase().trim();
// Default to yes if user just presses enter
resolve(response === '' || response === 'y' || response === 'yes');
});
});
shouldApply = answer;
}
if (shouldApply) {
writeFileSync(claudeMdPath, finalContent);
console.log(chalk.green(`ā Updated ${claudeMdPath}`));
console.log(chalk.green.bold('\n⨠Your personalized instructions are ready!\n'));
}
else {
console.log(chalk.yellow('\nā Changes discarded.\n'));
}
}
catch (error) {
spinner.fail('An error occurred');
console.error(chalk.red('\nError details:'), error instanceof Error ? error.message : String(error));
if (error instanceof Error && error.message.includes('claude')) {
console.log(chalk.yellow('\nš” Tip: Make sure the Claude CLI is installed:'));
console.log(chalk.gray(' npm install -g @anthropic-ai/claude-code'));
}
process.exit(1);
}
}
main();
//# sourceMappingURL=index.js.map