seo-generator-server/tools/analyze-skipped-exports.js
StillHammer 64fb319e65 refactor: Synchronisation complète du codebase - Application de tous les patches
Application systématique et méthodique de tous les patches historiques.

##  FICHIERS SYNCHRONISÉS (19 fichiers)

### Core & Infrastructure:
- server.js (14 patches) - Lazy loading ModeManager, SIGINT hard kill, timing logs
- ModeManager.js (4 patches) - Instrumentation complète avec timing détaillé

### Pipeline System:
- PipelineDefinition.js (6 patches) - Source unique getLLMProvidersList()
- pipeline-builder.js (8 patches) - Standardisation LLM providers
- pipeline-runner.js (6 patches) - Affichage résultats structurés + debug console
- pipeline-builder.html (2 patches) - Fallback providers synchronisés
- pipeline-runner.html (3 patches) - UI améliorée résultats

### Enhancement Layers:
- TechnicalLayer.js (1 patch) - defaultLLM: 'gpt-4o-mini'
- StyleLayer.js (1 patch) - Type safety vocabulairePref
- PatternBreakingCore.js (1 patch) - Mapping modifications
- PatternBreakingLayers.js (1 patch) - LLM standardisé

### Validators & Tests:
- QualityMetrics.js (1 patch) - callLLM('gpt-4o-mini')
- PersonalityValidator.js (1 patch) - Provider gpt-4o-mini
- AntiDetectionValidator.js - Synchronisé

### Documentation:
- TODO.md (1 patch) - Section LiteLLM pour tracking coûts
- CLAUDE.md - Documentation à jour

### Tools:
- tools/analyze-skipped-exports.js (nouveau)
- tools/apply-claude-exports.js (nouveau)
- tools/apply-claude-exports-fuzzy.js (nouveau)

## 🎯 Changements principaux:
-  Standardisation LLM providers (openai → gpt-4o-mini, claude → claude-sonnet-4-5)
-  Lazy loading optimisé (ModeManager chargé à la demande)
-  SIGINT immediate exit (pas de graceful shutdown)
-  Type safety renforcé (conversions string explicites)
-  Instrumentation timing complète
-  Debug logging amélioré (console.log résultats pipeline)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-12 20:36:17 +08:00

213 lines
8.0 KiB
JavaScript

#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const EXPORTS_DIR = path.join(__dirname, '../claude-exports-last-3-days');
/**
* Parse un fichier de session pour extraire les tool uses
*/
function parseSessionFile(filePath) {
const content = fs.readFileSync(filePath, 'utf-8');
const tools = [];
// Chercher tous les blocs JSON qui contiennent des tool uses
const jsonBlockRegex = /\[\s*\{[\s\S]*?"type":\s*"tool_use"[\s\S]*?\}\s*\]/g;
const matches = content.match(jsonBlockRegex);
if (!matches) return tools;
for (const match of matches) {
try {
const parsed = JSON.parse(match);
for (const item of parsed) {
if (item.type === 'tool_use' && (item.name === 'Edit' || item.name === 'Write')) {
tools.push({
name: item.name,
input: item.input
});
}
}
} catch (e) {
// Skip invalid JSON
}
}
return tools;
}
/**
* Analyse pourquoi un Edit a été skippé
*/
function analyzeSkippedEdit(filePath, oldString) {
if (!fs.existsSync(filePath)) {
return { reason: 'FILE_NOT_EXIST', details: 'Fichier n\'existe pas' };
}
const content = fs.readFileSync(filePath, 'utf-8');
if (!content.includes(oldString)) {
// Vérifier si une partie de old_string existe
const oldLines = oldString.split('\n').filter(l => l.trim());
const matchingLines = oldLines.filter(line => content.includes(line.trim()));
if (matchingLines.length > 0) {
return {
reason: 'PARTIAL_MATCH',
details: `${matchingLines.length}/${oldLines.length} lignes trouvées - code probablement modifié`
};
} else {
return {
reason: 'NO_MATCH',
details: 'Code complètement différent - changement déjà appliqué ou code refactorisé'
};
}
}
return { reason: 'OK', details: 'Devrait fonctionner' };
}
/**
* Main
*/
function main() {
console.log('🔍 Analyse des exports Claude skippés...\n');
const sessionFiles = fs.readdirSync(EXPORTS_DIR)
.filter(f => f.endsWith('-session.md'))
.sort((a, b) => {
const numA = parseInt(a.split('-')[0]);
const numB = parseInt(b.split('-')[0]);
return numB - numA;
});
const skippedAnalysis = {
FILE_NOT_EXIST: [],
PARTIAL_MATCH: [],
NO_MATCH: [],
FILE_EXISTS: [] // Pour les Write
};
let totalSkipped = 0;
for (const sessionFile of sessionFiles) {
const filePath = path.join(EXPORTS_DIR, sessionFile);
const tools = parseSessionFile(filePath);
for (const tool of tools) {
if (tool.name === 'Edit') {
const { file_path, old_string } = tool.input;
if (!fs.existsSync(file_path)) {
skippedAnalysis.FILE_NOT_EXIST.push({
session: sessionFile,
file: file_path,
preview: old_string.substring(0, 80)
});
totalSkipped++;
} else {
const content = fs.readFileSync(file_path, 'utf-8');
if (!content.includes(old_string)) {
const analysis = analyzeSkippedEdit(file_path, old_string);
if (analysis.reason === 'PARTIAL_MATCH') {
skippedAnalysis.PARTIAL_MATCH.push({
session: sessionFile,
file: file_path,
details: analysis.details,
preview: old_string.substring(0, 80)
});
} else {
skippedAnalysis.NO_MATCH.push({
session: sessionFile,
file: file_path,
preview: old_string.substring(0, 80)
});
}
totalSkipped++;
}
}
} else if (tool.name === 'Write') {
const { file_path } = tool.input;
if (fs.existsSync(file_path)) {
skippedAnalysis.FILE_EXISTS.push({
session: sessionFile,
file: file_path
});
totalSkipped++;
}
}
}
}
console.log(`📊 Total skippés: ${totalSkipped}\n`);
console.log('═══════════════════════════════════════════════════════');
console.log('🚫 FICHIERS N\'EXISTANT PAS (Edit)');
console.log(` ${skippedAnalysis.FILE_NOT_EXIST.length} cas\n`);
const fileNotExistByFile = {};
for (const item of skippedAnalysis.FILE_NOT_EXIST) {
if (!fileNotExistByFile[item.file]) {
fileNotExistByFile[item.file] = 0;
}
fileNotExistByFile[item.file]++;
}
Object.entries(fileNotExistByFile)
.sort((a, b) => b[1] - a[1])
.slice(0, 10)
.forEach(([file, count]) => {
console.log(` ${count}x - ${file}`);
});
console.log('\n═══════════════════════════════════════════════════════');
console.log('⚠️ CORRESPONDANCE PARTIELLE (Edit - code probablement modifié)');
console.log(` ${skippedAnalysis.PARTIAL_MATCH.length} cas\n`);
const partialByFile = {};
for (const item of skippedAnalysis.PARTIAL_MATCH) {
if (!partialByFile[item.file]) {
partialByFile[item.file] = 0;
}
partialByFile[item.file]++;
}
Object.entries(partialByFile)
.sort((a, b) => b[1] - a[1])
.slice(0, 10)
.forEach(([file, count]) => {
console.log(` ${count}x - ${file}`);
});
console.log('\n═══════════════════════════════════════════════════════');
console.log('❌ AUCUNE CORRESPONDANCE (Edit - changement déjà appliqué)');
console.log(` ${skippedAnalysis.NO_MATCH.length} cas\n`);
const noMatchByFile = {};
for (const item of skippedAnalysis.NO_MATCH) {
if (!noMatchByFile[item.file]) {
noMatchByFile[item.file] = 0;
}
noMatchByFile[item.file]++;
}
Object.entries(noMatchByFile)
.sort((a, b) => b[1] - a[1])
.slice(0, 10)
.forEach(([file, count]) => {
console.log(` ${count}x - ${file}`);
});
console.log('\n═══════════════════════════════════════════════════════');
console.log('✅ FICHIERS DÉJÀ EXISTANTS (Write - comportement normal)');
console.log(` ${skippedAnalysis.FILE_EXISTS.length} cas\n`);
skippedAnalysis.FILE_EXISTS.forEach(item => {
console.log(` ${item.session}${item.file}`);
});
console.log('\n═══════════════════════════════════════════════════════');
console.log('💡 CONCLUSION:\n');
console.log(` ✅ Write skippés: ${skippedAnalysis.FILE_EXISTS.length} (NORMAL - ne pas écraser)`);
console.log(` ❌ Edit skippés (NO_MATCH): ${skippedAnalysis.NO_MATCH.length} (changements déjà appliqués)`);
console.log(` ⚠️ Edit skippés (PARTIAL_MATCH): ${skippedAnalysis.PARTIAL_MATCH.length} (code modifié depuis)`);
console.log(` 🚫 Edit skippés (FILE_NOT_EXIST): ${skippedAnalysis.FILE_NOT_EXIST.length} (fichiers supprimés?)\n`);
}
main();