docstodev 1.0.3 → 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.
@@ -1,28 +1,66 @@
1
1
  // Emplacement absolu : M:\workspace\extensions\docstodev\src\ai\analyzer.ts
2
2
 
3
- import "dotenv/config"; // Pour lire GROQ_API_KEY dans ton .env
3
+ import "dotenv/config";
4
4
 
5
- export async function askAI(technicalContext: string) {
5
+ export interface AIAnalysisOptions {
6
+ language?: "fr" | "en";
7
+ includeDesignSystem?: boolean;
8
+ includeRisks?: boolean;
9
+ includeRecommendations?: boolean;
10
+ detailLevel?: "brief" | "detailed" | "comprehensive";
11
+ focusAreas?: ("architecture" | "security" | "performance" | "maintainability")[];
12
+ }
13
+
14
+ export interface AIAnalysisResult {
15
+ summary: string;
16
+ projectGoal?: string;
17
+ designSystem?: {
18
+ primaryColors: string[];
19
+ typography?: string;
20
+ componentPatterns?: string[];
21
+ };
22
+ risks?: Array<{ level: "low" | "medium" | "high"; description: string }>;
23
+ recommendations?: string[];
24
+ rawAnalysis: string;
25
+ }
26
+
27
+ export async function askAI(
28
+ technicalContext: string,
29
+ options: AIAnalysisOptions = {}
30
+ ): Promise<string> {
31
+ const result = await askAIDetailed(technicalContext, options);
32
+ return result.rawAnalysis;
33
+ }
34
+
35
+ export async function askAIDetailed(
36
+ technicalContext: string,
37
+ options: AIAnalysisOptions = {}
38
+ ): Promise<AIAnalysisResult> {
39
+ const {
40
+ language = "fr",
41
+ includeDesignSystem = true,
42
+ includeRisks = true,
43
+ includeRecommendations = true,
44
+ detailLevel = "detailed",
45
+ focusAreas = ["architecture", "maintainability"]
46
+ } = options;
6
47
 
7
- // clé par défaut gratuite
8
48
  const GROQ_API_KEY = process.env.GROQ_API_KEY || "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";
9
49
 
10
50
  if (!GROQ_API_KEY) {
11
- return "⚠️ Erreur : Clé API Groq manquante dans le fichier .env";
51
+ return {
52
+ summary: "⚠️ Erreur : Clé API Groq manquante",
53
+ rawAnalysis: "⚠️ Erreur : Clé API Groq manquante dans le fichier .env"
54
+ };
12
55
  }
13
56
 
14
- const systemPrompt = `
15
- Vous êtes MakazouIA, l'assistant IA de DocsToDev, créé par Chadrack Massamba (EsporDev).
16
- Votre mission : Transformer des données techniques brutes en descriptions métier claires.
17
-
18
- Instructions :
19
- - Vous allez recevoir une liste de fichiers, leurs rôles et leurs exports.
20
- - Pour chaque fichier, rédigez UNE SEULE phrase concise expliquant sa responsabilité métier.
21
- - Soyez pro, mais gardez votre touche amicale et votre pointe d'humour du Congo-Brazzaville.
22
- - mentionnez les imports, technique ( "il y a une fonction X"), expliquez le BUT du fichier.
23
- - selon le nombre d'occurance précisez les couleurs qui reviennen souvent eu suggérez un design systèm , pallette de couleur.
24
- - donnez une très bref description du but de l'ensemble du projet.
25
- `;
57
+ const systemPrompt = buildSystemPrompt(language, {
58
+ includeDesignSystem,
59
+ includeRisks,
60
+ includeRecommendations,
61
+ detailLevel,
62
+ focusAreas
63
+ });
26
64
 
27
65
  try {
28
66
  const resp = await fetch("https://api.groq.com/openai/v1/chat/completions", {
@@ -35,16 +73,217 @@ Instructions :
35
73
  model: "llama-3.3-70b-versatile",
36
74
  messages: [
37
75
  { role: "system", content: systemPrompt },
38
- { role: "user", content: `Voici les données techniques du projet : \n${technicalContext}` }
76
+ {
77
+ role: "user",
78
+ content: language === "fr"
79
+ ? `Voici les données techniques du projet :\n\n${technicalContext}`
80
+ : `Here is the technical project data:\n\n${technicalContext}`
81
+ }
39
82
  ],
40
83
  temperature: 0.7,
84
+ max_tokens: detailLevel === "comprehensive" ? 4096 : detailLevel === "detailed" ? 2048 : 1024
41
85
  }),
42
86
  });
43
87
 
44
88
  const data = await resp.json();
45
- return data.choices?.[0]?.message?.content || "Désolé, je n'ai pas pu analyser ce fichier.";
89
+ const rawAnalysis = data.choices?.[0]?.message?.content ||
90
+ (language === "fr" ? "Désolé, je n'ai pas pu analyser ce fichier." : "Sorry, I couldn't analyze this file.");
91
+
92
+ return parseAIResponse(rawAnalysis, options);
46
93
  } catch (error) {
47
94
  console.error("Erreur IA:", error);
48
- return "Erreur lors de la connexion à l'intelligence artificielle.";
95
+ return {
96
+ summary: language === "fr"
97
+ ? "Erreur lors de la connexion à l'intelligence artificielle."
98
+ : "Error connecting to artificial intelligence.",
99
+ rawAnalysis: language === "fr"
100
+ ? "Erreur lors de la connexion à l'intelligence artificielle."
101
+ : "Error connecting to artificial intelligence."
102
+ };
103
+ }
104
+ }
105
+
106
+ function buildSystemPrompt(
107
+ language: "fr" | "en",
108
+ options: {
109
+ includeDesignSystem: boolean;
110
+ includeRisks: boolean;
111
+ includeRecommendations: boolean;
112
+ detailLevel: string;
113
+ focusAreas: string[];
114
+ }
115
+ ): string {
116
+ const { includeDesignSystem, includeRisks, includeRecommendations, detailLevel, focusAreas } = options;
117
+
118
+ if (language === "fr") {
119
+ return `
120
+ Vous êtes **MakazouIA**, l'assistant IA de **DocsToDev**, créé par **Chadrack Massamba (EsporDev)**.
121
+ Votre mission : Transformer des données techniques brutes en documentation métier claire et structurée.
122
+
123
+ ## 📋 Instructions Générales
124
+ - Analysez les fichiers fournis et identifiez leur rôle métier précis.
125
+ - Rédigez des descriptions concises mais complètes (${detailLevel === "brief" ? "1 phrase" : detailLevel === "detailed" ? "2-3 phrases" : "paragraphe complet"}).
126
+ - Gardez un ton professionnel avec une touche amicale et une pointe d'humour du Congo-Brazzaville.
127
+ - Mentionnez les imports importants et expliquez le BUT métier de chaque fichier, pas seulement la technique.
128
+
129
+ ## 🎯 Structure de Réponse Requise
130
+
131
+ ### 1. **But du Projet** (Section prioritaire)
132
+ Rédigez UN paragraphe clair expliquant :
133
+ - L'objectif principal du projet
134
+ - Les problèmes qu'il résout
135
+ - Le public cible ou cas d'usage
136
+
137
+ ${includeDesignSystem ? `
138
+ ### 2. **Design System Détecté**
139
+ Analysez le code pour identifier :
140
+ - **Palette de couleurs** : Couleurs primaires/secondaires utilisées (avec codes hex si possibles)
141
+ - **Typographie** : Polices détectées
142
+ - **Patterns de composants** : Patterns UI récurrents (cards, modals, forms, etc.)
143
+ ` : ""}
144
+
145
+ ${includeRisks ? `
146
+ ### 3. **⚠️ Risques Identifiés**
147
+ Listez les risques potentiels classés par niveau :
148
+ - 🔴 **Critique** : Problèmes majeurs (sécurité, architecture)
149
+ - 🟡 **Moyen** : Points d'attention (dette technique, performance)
150
+ - 🟢 **Faible** : Améliorations mineures
151
+
152
+ Focus sur : ${focusAreas.join(", ")}
153
+ ` : ""}
154
+
155
+ ${includeRecommendations ? `
156
+ ### 4. **💡 Recommandations**
157
+ Proposez 3-5 actions concrètes pour améliorer le projet :
158
+ - Refactoring suggéré
159
+ - Optimisations possibles
160
+ - Bonnes pratiques à adopter
161
+ ` : ""}
162
+
163
+ ### 5. **Analyse Détaillée des Fichiers**
164
+ Pour chaque fichier majeur, expliquez :
165
+ - Son rôle métier principal
166
+ - Ses dépendances clés
167
+ - Son importance dans l'architecture globale
168
+
169
+ ## ⚡ Ton et Style
170
+ - Soyez technique mais accessible
171
+ - Utilisez des émojis judicieusement (📂 🔧 ⚠️ 💡)
172
+ - Pas de jargon inutile, privilégiez la clarté
173
+ `;
174
+ } else {
175
+ return `
176
+ You are **MakazouIA**, the AI assistant of **DocsToDev**, created by **Chadrack Massamba (EsporDev)**.
177
+ Your mission: Transform raw technical data into clear business documentation.
178
+
179
+ ## 📋 General Instructions
180
+ - Analyze provided files and identify their precise business role.
181
+ - Write concise yet complete descriptions (${detailLevel === "brief" ? "1 sentence" : detailLevel === "detailed" ? "2-3 sentences" : "full paragraph"}).
182
+ - Keep a professional tone with a friendly touch and a hint of Congo-Brazzaville humor.
183
+ - Mention important imports and explain the business PURPOSE of each file, not just the technical aspect.
184
+
185
+ ## 🎯 Required Response Structure
186
+
187
+ ### 1. **Project Goal** (Priority section)
188
+ Write ONE clear paragraph explaining:
189
+ - The main project objective
190
+ - Problems it solves
191
+ - Target audience or use cases
192
+
193
+ ${includeDesignSystem ? `
194
+ ### 2. **Detected Design System**
195
+ Analyze code to identify:
196
+ - **Color palette**: Primary/secondary colors used (with hex codes if possible)
197
+ - **Typography**: Detected fonts
198
+ - **Component patterns**: Recurring UI patterns (cards, modals, forms, etc.)
199
+ ` : ""}
200
+
201
+ ${includeRisks ? `
202
+ ### 3. **⚠️ Identified Risks**
203
+ List potential risks classified by level:
204
+ - 🔴 **Critical**: Major issues (security, architecture)
205
+ - 🟡 **Medium**: Points of attention (technical debt, performance)
206
+ - 🟢 **Low**: Minor improvements
207
+
208
+ Focus on: ${focusAreas.join(", ")}
209
+ ` : ""}
210
+
211
+ ${includeRecommendations ? `
212
+ ### 4. **💡 Recommendations**
213
+ Propose 3-5 concrete actions to improve the project:
214
+ - Suggested refactoring
215
+ - Possible optimizations
216
+ - Best practices to adopt
217
+ ` : ""}
218
+
219
+ ### 5. **Detailed File Analysis**
220
+ For each major file, explain:
221
+ - Its main business role
222
+ - Key dependencies
223
+ - Its importance in the overall architecture
224
+
225
+ ## ⚡ Tone and Style
226
+ - Be technical but accessible
227
+ - Use emojis judiciously (📂 🔧 ⚠️ 💡)
228
+ - No unnecessary jargon, prioritize clarity
229
+ `;
49
230
  }
231
+ }
232
+
233
+ function parseAIResponse(rawAnalysis: string, options: AIAnalysisOptions): AIAnalysisResult {
234
+ const result: AIAnalysisResult = {
235
+ summary: "",
236
+ rawAnalysis
237
+ };
238
+
239
+ // Extraire le but du projet
240
+ const goalMatch = rawAnalysis.match(/(?:But du Projet|Project Goal)[:\s]*\n+([\s\S]*?)(?=\n#{2,}|\n\n[A-Z#]|$)/i);
241
+ if (goalMatch) {
242
+ result.projectGoal = goalMatch[1]?.trim() || "";
243
+ }
244
+
245
+ // Extraire le design system
246
+ if (options.includeDesignSystem) {
247
+ const designMatch = rawAnalysis.match(/(?:Design System|Palette)[:\s]*\n+([\s\S]*?)(?=\n#{2,}|\n\n[A-Z#]|$)/i);
248
+ if (designMatch) {
249
+ const colors = designMatch[1]?.match(/#[0-9A-Fa-f]{6}/g) || [];
250
+ result.designSystem = {
251
+ primaryColors: colors,
252
+ componentPatterns: []
253
+ };
254
+ }
255
+ }
256
+
257
+ // Extraire les risques
258
+ if (options.includeRisks) {
259
+ const risksMatch = rawAnalysis.match(/(?:Risques|Risks)[:\s]*\n+([\s\S]*?)(?=\n#{2,}|\n\n[A-Z#]|$)/i);
260
+ if (risksMatch) {
261
+ result.risks = [];
262
+ const criticalMatches = risksMatch[1]?.match(/🔴[^\n]+/g) || [];
263
+ const mediumMatches = risksMatch[1]?.match(/🟡[^\n]+/g) || [];
264
+ const lowMatches = risksMatch[1]?.match(/🟢[^\n]+/g) || [];
265
+
266
+ criticalMatches.forEach(r => result.risks!.push({ level: "high", description: r.replace(/🔴\s*/, "") }));
267
+ mediumMatches.forEach(r => result.risks!.push({ level: "medium", description: r.replace(/🟡\s*/, "") }));
268
+ lowMatches.forEach(r => result.risks!.push({ level: "low", description: r.replace(/🟢\s*/, "") }));
269
+ }
270
+ }
271
+
272
+ // Extraire les recommandations
273
+ if (options.includeRecommendations) {
274
+ const recoMatch = rawAnalysis.match(/(?:Recommandations|Recommendations)[:\s]*\n+([\s\S]*?)(?=\n#{2,}|\n\n[A-Z#]|$)/i);
275
+ if (recoMatch && recoMatch[1]) {
276
+ result.recommendations = recoMatch[1]
277
+ .split(/\n[-*•]/)
278
+ .map(r => r.trim())
279
+ .filter(r => r.length > 10);
280
+ } else {
281
+ result.recommendations = [];
282
+ }
283
+ }
284
+
285
+ // Résumé (premiers 200 caractères)
286
+ result.summary = rawAnalysis.substring(0, 200).trim() + "...";
287
+
288
+ return result;
50
289
  }
@@ -4,7 +4,7 @@ import { writeFileSync, readFileSync, existsSync, mkdirSync } from "node:fs";
4
4
  import path from "node:path";
5
5
  import puppeteer, { Browser, Page } from "puppeteer";
6
6
  import { exportToHTML } from "../exporters/html.js";
7
- import { askAI } from "../ai/analyzer.js";
7
+ import { askAIDetailed, type AIAnalysisOptions } from "../ai/analyzer.js";
8
8
  import { getAnalyzer, getSupportedExtensions } from "../analyzers/languageAnalyzer.js";
9
9
  import { CacheManager } from "../cache/cacheManager.js";
10
10
 
@@ -14,7 +14,6 @@ interface FileAnalysis {
14
14
  path: string;
15
15
  lines: number;
16
16
  exports: string[];
17
- // Ajout de '| undefined' pour supporter les propriétés optionnelles en mode strict
18
17
  imports: Array<{ name: string; type: string; usage?: string | undefined }>;
19
18
  functions: string[];
20
19
  classes: string[];
@@ -36,7 +35,13 @@ const i18n = {
36
35
  functions: "Fonctions",
37
36
  classes: "Classes",
38
37
  types: "Types/Interfaces",
39
- complexity: "Score de complexité"
38
+ complexity: "Score de complexité",
39
+ projectGoal: "But du Projet",
40
+ designSystem: "Design System Détecté",
41
+ colorPalette: "Palette de couleurs",
42
+ componentPatterns: "Patterns de composants",
43
+ risks: "Risques Identifiés",
44
+ recommendations: "Recommandations"
40
45
  },
41
46
  en: {
42
47
  role: "Role and responsibilities",
@@ -51,7 +56,13 @@ const i18n = {
51
56
  functions: "Functions",
52
57
  classes: "Classes",
53
58
  types: "Types/Interfaces",
54
- complexity: "Complexity score"
59
+ complexity: "Complexity score",
60
+ projectGoal: "Project Goal",
61
+ designSystem: "Detected Design System",
62
+ colorPalette: "Color Palette",
63
+ componentPatterns: "Component Patterns",
64
+ risks: "Identified Risks",
65
+ recommendations: "Recommendations"
55
66
  }
56
67
  };
57
68
 
@@ -92,43 +103,30 @@ function analyzeFile(file: string, content: string): FileAnalysis {
92
103
  const lines = content.split(/\r?\n/);
93
104
  const analyzer = getAnalyzer(file);
94
105
 
95
- if (analyzer) {
96
- const result = analyzer.analyzeFile(content);
97
-
98
- const ifCount = (content.match(/\b(if|elif|else if)\s*\(/g) || []).length;
99
- const forCount = (content.match(/\b(for|foreach|while)\s*\(/g) || []).length;
100
- const whileCount = (content.match(/\bwhile\s*\(/g) || []).length;
101
-
102
- const complexity =
103
- lines.length * 0.1 +
104
- result.functions.length * 2 +
105
- result.classes.length * 3 +
106
- result.imports.length * 1.5 +
107
- ifCount * 1 +
108
- forCount * 1.5 +
109
- whileCount * 1.5;
110
-
111
- return {
112
- path: file,
113
- lines: lines.length,
114
- exports: result.exports,
115
- imports: result.imports,
116
- functions: result.functions,
117
- classes: result.classes,
118
- types: result.types,
119
- complexity: Math.round(complexity)
120
- };
121
- }
106
+ const result = analyzer.analyzeFile(content);
107
+
108
+ const ifCount = (content.match(/\b(if|elif|else if)\s*\(/g) || []).length;
109
+ const forCount = (content.match(/\b(for|foreach|while)\s*\(/g) || []).length;
110
+ const whileCount = (content.match(/\bwhile\s*\(/g) || []).length;
111
+
112
+ const complexity =
113
+ lines.length * 0.1 +
114
+ result.functions.length * 2 +
115
+ result.classes.length * 3 +
116
+ result.imports.length * 1.5 +
117
+ ifCount * 1 +
118
+ forCount * 1.5 +
119
+ whileCount * 1.5;
122
120
 
123
121
  return {
124
122
  path: file,
125
123
  lines: lines.length,
126
- exports: [],
127
- imports: [],
128
- functions: [],
129
- classes: [],
130
- types: [],
131
- complexity: 0
124
+ exports: result.exports,
125
+ imports: result.imports,
126
+ functions: result.functions,
127
+ classes: result.classes,
128
+ types: result.types,
129
+ complexity: Math.round(complexity)
132
130
  };
133
131
  }
134
132
 
@@ -140,7 +138,7 @@ function getComplexityLevel(score: number): string {
140
138
  }
141
139
 
142
140
  function formatAISummary(summary: string): string {
143
- let formatted = summary.replace(/([a-zA-Z0-9_-]+\.(ts|js|py|java|cs|go|rs|tsx|jsx|mjs|cjs))/g, '`$1`');
141
+ let formatted = summary.replace(/([a-zA-Z0-9_-]+\.(ts|js|py|java|cs|go|rs|tsx|jsx|mjs|cjs|html|css|php|rb|sql))/g, '`$1`');
144
142
  formatted = formatted.replace(/([a-zA-Z0-9_-]+\/[a-zA-Z0-9_\/-]+)/g, '`$1`');
145
143
  formatted = formatted.replace(/\b([a-z][a-zA-Z0-9]*[A-Z][a-zA-Z0-9]*|[A-Z][a-z][a-zA-Z0-9]*)\b/g, '`$1`');
146
144
  formatted = formatted.replace(/\.\s+/g, '.\n\n');
@@ -150,7 +148,11 @@ function formatAISummary(summary: string): string {
150
148
 
151
149
  export async function runCommand(
152
150
  language: "fr" | "en" = "fr",
153
- options: { incremental?: boolean; clearCache?: boolean } = {}
151
+ options: {
152
+ incremental?: boolean;
153
+ clearCache?: boolean;
154
+ aiOptions?: AIAnalysisOptions;
155
+ } = {}
154
156
  ): Promise<number> {
155
157
  const t = i18n[language];
156
158
 
@@ -167,7 +169,7 @@ export async function runCommand(
167
169
  console.log(" ✓ Cache vidé\n");
168
170
  }
169
171
 
170
- console.log("📂 Étape 1/6 : Scan des fichiers du projet...");
172
+ console.log("📂 Étape 1/5 : Scan des fichiers du projet...");
171
173
  const supportedExts = getSupportedExtensions();
172
174
  const files = await globby(["**/*"], {
173
175
  gitignore: true,
@@ -198,9 +200,15 @@ export async function runCommand(
198
200
  console.log(` ✓ ${modifiedFiles.length} fichiers modifiés, ${cachedCount} en cache\n`);
199
201
  }
200
202
 
201
- console.log("🔍 Étape 2/6 : Analyse approfondie des fichiers sources...");
202
- let aiContext = `Tu es un expert en analyse de code. Analyse ces fichiers et explique leur architecture, leurs responsabilités et comment ils collaborent ensemble. Identifie le rôle de chaque fichier (Page, Component, Service, API, Utility, etc.). Sois précis et technique.\n\n`;
203
- let detailContent = `## 🔬 Analyse détaillée des composants\n\n`;
203
+ console.log("🔍 Étape 2/5 : Analyse approfondie des fichiers sources...");
204
+ let aiContext = language === "fr"
205
+ ? `Tu es un expert en analyse de code. Analyse ces fichiers et explique leur architecture, leurs responsabilités et comment ils collaborent ensemble. Identifie le rôle de chaque fichier (Page, Component, Service, API, Utility, etc.). Sois précis et technique.\n\n`
206
+ : `You are a code analysis expert. Analyze these files and explain their architecture, responsibilities and how they work together. Identify the role of each file (Page, Component, Service, API, Utility, etc.). Be precise and technical.\n\n`;
207
+
208
+ let detailContent = language === "fr"
209
+ ? `## 🔬 Analyse détaillée des composants\n\n`
210
+ : `## 🔬 Detailed Component Analysis\n\n`;
211
+
204
212
  let mermaidGraph = "graph LR\n";
205
213
  const allDeps = new Map<string, string>();
206
214
  const analyses: FileAnalysis[] = [];
@@ -283,25 +291,83 @@ export async function runCommand(
283
291
  const totalAnalyzed = processedCount + cachedCount;
284
292
  console.log(` ✓ ${totalAnalyzed} fichiers analysés (${processedCount} nouvelles analyses, ${cachedCount} depuis cache)\n`);
285
293
 
286
- console.log("🤖 Étape 3/6 : Génération de l'analyse intelligente (IA)...");
287
- const aiSummary = await askAI(aiContext) || "⚠️ Analyse IA indisponible. Vérifiez votre configuration.";
288
- const formattedAiSummary = formatAISummary(aiSummary);
294
+ console.log("🤖 Étape 3/5 : Génération de l'analyse intelligente (IA)...");
295
+
296
+ const aiOptions: AIAnalysisOptions = options.aiOptions || {
297
+ language,
298
+ includeDesignSystem: true,
299
+ includeRisks: true,
300
+ includeRecommendations: true,
301
+ detailLevel: "detailed",
302
+ focusAreas: ["architecture", "maintainability", "security"]
303
+ };
304
+
305
+ const aiResult = await askAIDetailed(aiContext, aiOptions);
306
+ const formattedAiSummary = formatAISummary(aiResult.rawAnalysis);
307
+
289
308
  console.log(` ✓ Synthèse IA générée\n`);
290
309
 
291
- console.log("📝 Étape 4/6 : Construction du rapport Markdown...");
310
+ console.log("📝 Étape 4/5 : Construction du rapport Markdown...");
292
311
  let finalMD = `# ${t.reportTitle}\n\n`;
293
- finalMD += `> 📅 ${t.genAt} : ${new Date().toLocaleString("fr-FR", { dateStyle: "full", timeStyle: "short" })}\n`;
312
+ finalMD += `> 📅 ${t.genAt} : ${new Date().toLocaleString(language === "fr" ? "fr-FR" : "en-US", { dateStyle: "full", timeStyle: "short" })}\n`;
294
313
  finalMD += `> 📊 ${totalAnalyzed} fichiers analysés • ${allDeps.size} dépendances identifiées\n`;
295
314
  if (options.incremental && cachedCount > 0) {
296
315
  finalMD += `> ⚡ Mode incrémental : ${cachedCount} fichiers depuis cache\n`;
297
316
  }
298
317
  finalMD += `\n`;
318
+
319
+ // Section BUT DU PROJET (PRIORITÉ ABSOLUE)
320
+ if (aiResult.projectGoal) {
321
+ finalMD += `## 🎯 ${t.projectGoal}\n\n`;
322
+ finalMD += `${aiResult.projectGoal}\n\n`;
323
+ }
324
+
325
+ // Section DESIGN SYSTEM
326
+ if (aiResult.designSystem && aiOptions.includeDesignSystem) {
327
+ finalMD += `## 🎨 ${t.designSystem}\n\n`;
328
+ if (aiResult.designSystem.primaryColors && aiResult.designSystem.primaryColors.length > 0) {
329
+ finalMD += `**${t.colorPalette}** : ${aiResult.designSystem.primaryColors.join(", ")}\n\n`;
330
+ }
331
+ if (aiResult.designSystem.typography) {
332
+ finalMD += `**Typographie** : ${aiResult.designSystem.typography}\n\n`;
333
+ }
334
+ if (aiResult.designSystem.componentPatterns && aiResult.designSystem.componentPatterns.length > 0) {
335
+ finalMD += `**${t.componentPatterns}** : ${aiResult.designSystem.componentPatterns.join(", ")}\n\n`;
336
+ }
337
+ }
338
+
339
+ // Section RISQUES
340
+ if (aiResult.risks && aiOptions.includeRisks && aiResult.risks.length > 0) {
341
+ finalMD += `## ⚠️ ${t.risks}\n\n`;
342
+ aiResult.risks.forEach(risk => {
343
+ const icon = risk.level === "high" ? "🔴" : risk.level === "medium" ? "🟡" : "🟢";
344
+ const levelText = risk.level === "high" ? "CRITIQUE" : risk.level === "medium" ? "MOYEN" : "FAIBLE";
345
+ finalMD += `${icon} **${levelText}** : ${risk.description}\n\n`;
346
+ });
347
+ }
348
+
349
+ // Section RECOMMANDATIONS
350
+ if (aiResult.recommendations && aiOptions.includeRecommendations && aiResult.recommendations.length > 0) {
351
+ finalMD += `## 💡 ${t.recommendations}\n\n`;
352
+ aiResult.recommendations.forEach(reco => {
353
+ finalMD += `- ${reco}\n`;
354
+ });
355
+ finalMD += `\n`;
356
+ }
357
+
358
+ // Analyse IA complète
299
359
  finalMD += `## 💡 ${t.aiTitle}\n\n${formattedAiSummary}\n\n`;
360
+
361
+ // Structure du projet
300
362
  finalMD += `## 📂 ${t.structure}\n\n`;
301
363
  finalMD += "```\n";
302
364
  finalMD += renderTree(buildTree(files));
303
365
  finalMD += "```\n\n";
366
+
367
+ // Analyse détaillée
304
368
  finalMD += detailContent;
369
+
370
+ // Dépendances
305
371
  finalMD += `## 📦 ${t.deps}\n\n`;
306
372
  finalMD += `| Module | Type | Occurrences |\n`;
307
373
  finalMD += `| :--- | :--- | :---: |\n`;
@@ -322,14 +388,14 @@ export async function runCommand(
322
388
  writeFileSync(path.join(docsDir, "docs-to-dev.md"), finalMD);
323
389
  console.log(` ✓ Rapport Markdown généré : docs/docs-to-dev.md\n`);
324
390
 
325
- console.log("🎨 Étape 5/6 : Export HTML avec graphiques...");
391
+ console.log("🎨 Étape 5/5 : Export HTML avec graphiques...");
326
392
  const fileTreeStructure = buildTree(files);
327
393
  exportToHTML(docsDir, finalMD, mermaidGraph, language, fileTreeStructure);
328
394
  console.log(` ✓ Rapport HTML généré : docs/report.html\n`);
329
395
 
330
- console.log("📄 Étape 6/6 : Génération du PDF...");
331
- await generatePDF(path.join(docsDir, "report.html"), path.join(docsDir, "report.pdf"));
332
- console.log(` ✓ PDF exporté : docs/report.pdf\n`);
396
+ // console.log("📄 Étape 6/6 : Génération du PDF...");
397
+ // await generatePDF(path.join(docsDir, "report.html"), path.join(docsDir, "report.pdf"));
398
+ // console.log(` ✓ PDF exporté : docs/report.pdf\n`);
333
399
 
334
400
  console.log("╔══════════════════════════════════════════╗");
335
401
  console.log("║ ✨ Analyse terminée avec succès ! ║");
@@ -355,39 +421,39 @@ export async function runCommand(
355
421
  return files.length;
356
422
  }
357
423
 
358
- async function generatePDF(htmlPath: string, outputPath: string): Promise<void> {
359
- let browser: Browser | null = null;
360
- try {
361
- browser = await puppeteer.launch({
362
- headless: true,
363
- args: ['--no-sandbox', '--disable-setuid-sandbox']
364
- });
365
- const page: Page = await browser.newPage();
424
+ // async function generatePDF(htmlPath: string, outputPath: string): Promise<void> {
425
+ // let browser: Browser | null = null;
426
+ // try {
427
+ // browser = await puppeteer.launch({
428
+ // headless: true,
429
+ // args: ['--no-sandbox', '--disable-setuid-sandbox']
430
+ // });
431
+ // const page: Page = await browser.newPage();
366
432
 
367
- await page.goto(`file://${path.resolve(htmlPath)}`, {
368
- waitUntil: "networkidle0",
369
- timeout: 30000
370
- });
433
+ // await page.goto(`file://${path.resolve(htmlPath)}`, {
434
+ // waitUntil: "networkidle0",
435
+ // timeout: 30000
436
+ // });
371
437
 
372
- await page.waitForFunction(() => {
373
- return typeof (window as any).mermaid !== 'undefined';
374
- }, { timeout: 5000 }).catch(() => {});
438
+ // await page.waitForFunction(() => {
439
+ // return typeof (window as any).mermaid !== 'undefined';
440
+ // }, { timeout: 5000 }).catch(() => {});
375
441
 
376
- await new Promise(resolve => setTimeout(resolve, 2000));
442
+ // await new Promise(resolve => setTimeout(resolve, 2000));
377
443
 
378
- await page.pdf({
379
- path: outputPath,
380
- format: 'A4',
381
- printBackground: true,
382
- margin: { top: '1cm', bottom: '1cm', left: '1cm', right: '1cm' },
383
- preferCSSPageSize: true
384
- });
444
+ // await page.pdf({
445
+ // path: outputPath,
446
+ // format: 'A4',
447
+ // printBackground: true,
448
+ // margin: { top: '1cm', bottom: '1cm', left: '1cm', right: '1cm' },
449
+ // preferCSSPageSize: true
450
+ // });
385
451
 
386
- await browser.close();
387
- } catch (e) {
388
- console.error(" ⚠️ Erreur lors de la génération du PDF:", e);
389
- if (browser) {
390
- await browser.close().catch(() => {});
391
- }
392
- }
393
- }
452
+ // await browser.close();
453
+ // } catch (e) {
454
+ // console.error(" ⚠️ Erreur lors de la génération du PDF:", e);
455
+ // if (browser) {
456
+ // await browser.close().catch(() => {});
457
+ // }
458
+ // }
459
+ // }