scaffold-doc-cli 1.0.6 → 1.0.8
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/index.js +89 -53
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -69,25 +69,25 @@ async function init() {
|
|
|
69
69
|
-->
|
|
70
70
|
# ${answers.projectName} Documentation
|
|
71
71
|
|
|
72
|
-
##
|
|
72
|
+
## Vue d'ensemble
|
|
73
73
|
<!-- AI_CONTENT_START -->
|
|
74
|
-
Documentation
|
|
74
|
+
Documentation initialisée.
|
|
75
75
|
<!-- AI_CONTENT_END -->
|
|
76
76
|
|
|
77
|
-
##
|
|
78
|
-
- [
|
|
77
|
+
## Liens Rapides
|
|
78
|
+
- [Démarrage](./getting-started.md)
|
|
79
79
|
- [Architecture](./architecture.md)
|
|
80
80
|
`;
|
|
81
81
|
await fs.writeFile(path.join(docsDir, 'index.md'), indexContent);
|
|
82
82
|
|
|
83
83
|
// getting-started.md
|
|
84
|
-
const gettingStartedContent = `#
|
|
84
|
+
const gettingStartedContent = `# Démarrage
|
|
85
85
|
|
|
86
86
|
<!--
|
|
87
|
-
INSTRUCTION:
|
|
87
|
+
INSTRUCTION: Documentez les étapes d'installation et de configuration.
|
|
88
88
|
-->
|
|
89
89
|
|
|
90
|
-
##
|
|
90
|
+
## Prérequis
|
|
91
91
|
<!-- AI_CONTENT_START -->
|
|
92
92
|
<!-- AI_CONTENT_END -->
|
|
93
93
|
|
|
@@ -137,10 +137,10 @@ docs_dir: .docs
|
|
|
137
137
|
theme: readthedocs
|
|
138
138
|
|
|
139
139
|
nav:
|
|
140
|
-
-
|
|
141
|
-
-
|
|
140
|
+
- Accueil: index.md
|
|
141
|
+
- Démarrage: getting-started.md
|
|
142
142
|
- Architecture: architecture.md
|
|
143
|
-
-
|
|
143
|
+
- Référence:
|
|
144
144
|
${referenceNav}
|
|
145
145
|
`;
|
|
146
146
|
await fs.writeFile(path.join(process.cwd(), 'mkdocs.yml'), mkdocsContent);
|
|
@@ -189,7 +189,8 @@ jobs:
|
|
|
189
189
|
run: node .github/scripts/doc-sync.mjs
|
|
190
190
|
|
|
191
191
|
- name: Create Pull Request
|
|
192
|
-
|
|
192
|
+
id: cpr
|
|
193
|
+
uses: peter-evans/create-pull-request@v7
|
|
193
194
|
with:
|
|
194
195
|
token: \${{ secrets.GITHUB_TOKEN }}
|
|
195
196
|
commit-message: "docs: auto-generated documentation updates"
|
|
@@ -202,6 +203,12 @@ jobs:
|
|
|
202
203
|
base: \${{ github.head_ref || github.ref_name }}
|
|
203
204
|
delete-branch: true
|
|
204
205
|
add-paths: .docs
|
|
206
|
+
|
|
207
|
+
- name: Check outputs
|
|
208
|
+
if: \${{ steps.cpr.outputs.pull-request-number }}
|
|
209
|
+
run: |
|
|
210
|
+
echo "Pull Request Number - \${{ steps.cpr.outputs.pull-request-number }}"
|
|
211
|
+
echo "Pull Request URL - \${{ steps.cpr.outputs.pull-request-url }}"
|
|
205
212
|
`;
|
|
206
213
|
await fs.writeFile(path.join(workflowDir, 'ai-doc-sync.yml'), workflowContent);
|
|
207
214
|
console.log(chalk.green('✔ .github/workflows/ai-doc-sync.yml created'));
|
|
@@ -217,13 +224,22 @@ const genAI = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
|
|
|
217
224
|
async function main() {
|
|
218
225
|
console.log("Starting AI Doc Sync...");
|
|
219
226
|
|
|
227
|
+
// 1. Detect Changed Files
|
|
220
228
|
// 1. Detect Changed Files
|
|
221
229
|
let changedFiles = [];
|
|
230
|
+
let forceRegenerate = false;
|
|
231
|
+
|
|
222
232
|
try {
|
|
223
|
-
const
|
|
224
|
-
|
|
233
|
+
const commitMsg = execSync('git log -1 --pretty=%B').toString();
|
|
234
|
+
if (commitMsg.includes('regenerate-doc')) {
|
|
235
|
+
console.log('Trigger "regenerate-doc" détecté. Synchronisation de tous les fichiers...');
|
|
236
|
+
forceRegenerate = true;
|
|
237
|
+
}
|
|
225
238
|
} catch (e) {
|
|
226
|
-
|
|
239
|
+
// Ignore error
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (forceRegenerate) {
|
|
227
243
|
try {
|
|
228
244
|
const output = execSync('git ls-tree -r HEAD --name-only').toString();
|
|
229
245
|
changedFiles = output.split('\\n').filter(f => f && !f.startsWith('.docs') && !f.startsWith('.github'));
|
|
@@ -231,6 +247,20 @@ async function main() {
|
|
|
231
247
|
console.error("Failed to list files:", err.message);
|
|
232
248
|
return;
|
|
233
249
|
}
|
|
250
|
+
} else {
|
|
251
|
+
try {
|
|
252
|
+
const output = execSync('git diff --name-only HEAD~1 HEAD 2>/dev/null').toString();
|
|
253
|
+
changedFiles = output.split('\\n').filter(f => f && !f.startsWith('.docs') && !f.startsWith('.github'));
|
|
254
|
+
} catch (e) {
|
|
255
|
+
console.warn("HEAD~1 not found (likely first commit). Syncing all tracked files...");
|
|
256
|
+
try {
|
|
257
|
+
const output = execSync('git ls-tree -r HEAD --name-only').toString();
|
|
258
|
+
changedFiles = output.split('\\n').filter(f => f && !f.startsWith('.docs') && !f.startsWith('.github'));
|
|
259
|
+
} catch (err) {
|
|
260
|
+
console.error("Failed to list files:", err.message);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
234
264
|
}
|
|
235
265
|
|
|
236
266
|
if (changedFiles.length === 0) {
|
|
@@ -250,27 +280,33 @@ async function main() {
|
|
|
250
280
|
}
|
|
251
281
|
|
|
252
282
|
// 3. Prompt Gemini
|
|
253
|
-
|
|
254
|
-
|
|
283
|
+
// 3. Prompt Gemini (using @google/genai SDK)
|
|
284
|
+
// No need to get model instance first in this SDK version based on user snippet
|
|
285
|
+
|
|
286
|
+
|
|
255
287
|
const prompt = \`
|
|
256
|
-
|
|
257
|
-
|
|
288
|
+
Tu es un assistant de documentation technique expert.
|
|
289
|
+
Analyse les modifications de code suivantes et mets à jour la documentation dans le dossier .docs/.
|
|
258
290
|
|
|
259
|
-
|
|
260
|
-
1.
|
|
261
|
-
2.
|
|
262
|
-
3.
|
|
263
|
-
4.
|
|
264
|
-
5.
|
|
265
|
-
|
|
266
|
-
|
|
291
|
+
Règles:
|
|
292
|
+
1. La langue de sortie DOIT être le FRANÇAIS.
|
|
293
|
+
2. La sortie DOIT être un objet JSON valide où les clés sont les chemins de fichiers (relatifs à .docs/, ex: "reference/controllers.md") et les valeurs sont le NOUVEAU contenu de ce fichier.
|
|
294
|
+
3. Tu peux créer de nouveaux fichiers si nécessaire.
|
|
295
|
+
4. Tu peux mettre à jour les fichiers existants (ex: getting-started.md, architecture.md).
|
|
296
|
+
5. Concentre-toi sur la précision et la clarté.
|
|
297
|
+
6. N'inclus PAS de blocs de code markdown dans ta réponse, juste la chaîne JSON brute.
|
|
298
|
+
|
|
299
|
+
Contexte du code:
|
|
267
300
|
\${context}
|
|
268
301
|
\`;
|
|
269
302
|
|
|
270
303
|
try {
|
|
271
|
-
const result = await
|
|
272
|
-
|
|
273
|
-
|
|
304
|
+
const result = await genAI.models.generateContent({
|
|
305
|
+
model: "gemini-2.5-flash",
|
|
306
|
+
contents: prompt
|
|
307
|
+
});
|
|
308
|
+
const text = result.text;
|
|
309
|
+
|
|
274
310
|
// Simple cleanup if model adds code blocks
|
|
275
311
|
const jsonStr = text.replace(/\\\`\\\`\\\`json/g, '').replace(/\\\`\\\`\\\`/g, '').trim();
|
|
276
312
|
const updates = JSON.parse(jsonStr);
|
|
@@ -279,11 +315,11 @@ async function main() {
|
|
|
279
315
|
for (const [relativePath, content] of Object.entries(updates)) {
|
|
280
316
|
const fullPath = path.join(process.cwd(), '.docs', relativePath);
|
|
281
317
|
const dir = path.dirname(fullPath);
|
|
282
|
-
|
|
318
|
+
|
|
283
319
|
if (!fs.existsSync(dir)) {
|
|
284
320
|
fs.mkdirSync(dir, { recursive: true });
|
|
285
321
|
}
|
|
286
|
-
|
|
322
|
+
|
|
287
323
|
fs.writeFileSync(fullPath, content);
|
|
288
324
|
console.log(\`Updated: .docs/\${relativePath}\`);
|
|
289
325
|
}
|
|
@@ -322,9 +358,9 @@ function getStackConfig(stack) {
|
|
|
322
358
|
if (stack.includes('Symfony')) {
|
|
323
359
|
return {
|
|
324
360
|
files: {
|
|
325
|
-
'controllers.md': () => `${commonHeader('Controllers')}#
|
|
326
|
-
'entities.md': () => `${commonHeader('Entities')}#
|
|
327
|
-
'services.md': () => `${commonHeader('Services')}# Services\n\n<!-- INSTRUCTION:
|
|
361
|
+
'controllers.md': () => `${commonHeader('Controllers')}# Contrôleurs\n\n<!-- INSTRUCTION: Documentez tous les contrôleurs Symfony trouvés dans /src/Controller -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
362
|
+
'entities.md': () => `${commonHeader('Entities')}# Entités\n\n<!-- INSTRUCTION: Documentez toutes les entités Doctrine trouvées dans /src/Entity -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
363
|
+
'services.md': () => `${commonHeader('Services')}# Services\n\n<!-- INSTRUCTION: Documentez les services principaux trouvés dans /src/Service -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
328
364
|
}
|
|
329
365
|
};
|
|
330
366
|
}
|
|
@@ -333,9 +369,9 @@ function getStackConfig(stack) {
|
|
|
333
369
|
if (stack.includes('Laravel')) {
|
|
334
370
|
return {
|
|
335
371
|
files: {
|
|
336
|
-
'controllers.md': () => `${commonHeader('Controllers')}#
|
|
337
|
-
'models.md': () => `${commonHeader('Models')}#
|
|
338
|
-
'routes.md': () => `${commonHeader('Routes')}# Routes\n\n<!-- INSTRUCTION:
|
|
372
|
+
'controllers.md': () => `${commonHeader('Controllers')}# Contrôleurs\n\n<!-- INSTRUCTION: Documentez les contrôleurs Http trouvés dans /app/Http/Controllers -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
373
|
+
'models.md': () => `${commonHeader('Models')}# Modèles\n\n<!-- INSTRUCTION: Documentez les modèles Eloquent trouvés dans /app/Models -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
374
|
+
'routes.md': () => `${commonHeader('Routes')}# Routes\n\n<!-- INSTRUCTION: Documentez les routes trouvées dans /routes -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
339
375
|
}
|
|
340
376
|
};
|
|
341
377
|
}
|
|
@@ -344,9 +380,9 @@ function getStackConfig(stack) {
|
|
|
344
380
|
if (stack.includes('Nuxt')) {
|
|
345
381
|
return {
|
|
346
382
|
files: {
|
|
347
|
-
'components.md': () => `${commonHeader('Components')}#
|
|
348
|
-
'composables.md': () => `${commonHeader('Composables')}# Composables\n\n<!-- INSTRUCTION:
|
|
349
|
-
'server-routes.md': () => `${commonHeader('Server Routes')}#
|
|
383
|
+
'components.md': () => `${commonHeader('Components')}# Composants\n\n<!-- INSTRUCTION: Documentez les composants Vue dans /components -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
384
|
+
'composables.md': () => `${commonHeader('Composables')}# Composables\n\n<!-- INSTRUCTION: Documentez les composables auto-importés dans /composables -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
385
|
+
'server-routes.md': () => `${commonHeader('Server Routes')}# Routes Serveur\n\n<!-- INSTRUCTION: Documentez les routes serveur Nitro dans /server/api -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
350
386
|
}
|
|
351
387
|
};
|
|
352
388
|
}
|
|
@@ -355,9 +391,9 @@ function getStackConfig(stack) {
|
|
|
355
391
|
if (stack.includes('React') || stack.includes('Next') || stack.includes('Vue') || stack.includes('Angular') || stack.includes('Svelte')) {
|
|
356
392
|
return {
|
|
357
393
|
files: {
|
|
358
|
-
'components.md': () => `${commonHeader('Components')}#
|
|
359
|
-
'hooks.md': () => `${commonHeader('Hooks')}# Hooks\n\n<!-- INSTRUCTION:
|
|
360
|
-
'api.md': () => `${commonHeader('API')}# API
|
|
394
|
+
'components.md': () => `${commonHeader('Components')}# Composants\n\n<!-- INSTRUCTION: Documentez les composants UI -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
395
|
+
'hooks.md': () => `${commonHeader('Hooks')}# Hooks\n\n<!-- INSTRUCTION: Documentez les hooks personnalisés -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
396
|
+
'api.md': () => `${commonHeader('API')}# Intégration API\n\n<!-- INSTRUCTION: Documentez les clients API -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
361
397
|
}
|
|
362
398
|
};
|
|
363
399
|
}
|
|
@@ -366,9 +402,9 @@ function getStackConfig(stack) {
|
|
|
366
402
|
if (stack.includes('Django')) {
|
|
367
403
|
return {
|
|
368
404
|
files: {
|
|
369
|
-
'models.md': () => `${commonHeader('Models')}#
|
|
370
|
-
'views.md': () => `${commonHeader('Views')}#
|
|
371
|
-
'admin.md': () => `${commonHeader('Admin')}#
|
|
405
|
+
'models.md': () => `${commonHeader('Models')}# Modèles\n\n<!-- INSTRUCTION: Documentez les modèles Django -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
406
|
+
'views.md': () => `${commonHeader('Views')}# Vues\n\n<!-- INSTRUCTION: Documentez les Vues/ViewSets Django -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
407
|
+
'admin.md': () => `${commonHeader('Admin')}# Administration\n\n<!-- INSTRUCTION: Documentez les classes d'administration -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
372
408
|
}
|
|
373
409
|
};
|
|
374
410
|
}
|
|
@@ -377,8 +413,8 @@ function getStackConfig(stack) {
|
|
|
377
413
|
if (stack.includes('FastAPI')) {
|
|
378
414
|
return {
|
|
379
415
|
files: {
|
|
380
|
-
'endpoints.md': () => `${commonHeader('Endpoints')}# Endpoints\n\n<!-- INSTRUCTION:
|
|
381
|
-
'models.md': () => `${commonHeader('Models')}# Pydantic
|
|
416
|
+
'endpoints.md': () => `${commonHeader('Endpoints')}# Endpoints\n\n<!-- INSTRUCTION: Documentez les routes et décorateurs FastAPI -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
417
|
+
'models.md': () => `${commonHeader('Models')}# Modèles Pydantic\n\n<!-- INSTRUCTION: Documentez les modèles Pydantic -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
382
418
|
}
|
|
383
419
|
};
|
|
384
420
|
}
|
|
@@ -387,9 +423,9 @@ function getStackConfig(stack) {
|
|
|
387
423
|
if (stack.includes('Spring') || stack.includes('Java')) {
|
|
388
424
|
return {
|
|
389
425
|
files: {
|
|
390
|
-
'controllers.md': () => `${commonHeader('Controllers')}#
|
|
391
|
-
'services.md': () => `${commonHeader('Services')}# Services\n\n<!-- INSTRUCTION:
|
|
392
|
-
'domain.md': () => `${commonHeader('Domain')}#
|
|
426
|
+
'controllers.md': () => `${commonHeader('Controllers')}# Contrôleurs\n\n<!-- INSTRUCTION: Documentez les contrôleurs REST -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
427
|
+
'services.md': () => `${commonHeader('Services')}# Services\n\n<!-- INSTRUCTION: Documentez les beans Service -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
428
|
+
'domain.md': () => `${commonHeader('Domain')}# Modèles de Domaine\n\n<!-- INSTRUCTION: Documentez les classes d'Entité -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
393
429
|
}
|
|
394
430
|
};
|
|
395
431
|
}
|
|
@@ -397,8 +433,8 @@ function getStackConfig(stack) {
|
|
|
397
433
|
// --- Default Fallback ---
|
|
398
434
|
return {
|
|
399
435
|
files: {
|
|
400
|
-
'api.md': () => `${commonHeader('API')}# API
|
|
401
|
-
'modules.md': () => `${commonHeader('Modules')}#
|
|
436
|
+
'api.md': () => `${commonHeader('API')}# Référence API\n\n<!-- INSTRUCTION: Documentez les endpoints API publics -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
437
|
+
'modules.md': () => `${commonHeader('Modules')}# Modules principaux\n\n<!-- INSTRUCTION: Documentez les modules logiques principaux -->\n\n## Liste\n<!-- AI_CONTENT_START -->\n<!-- AI_CONTENT_END -->`,
|
|
402
438
|
}
|
|
403
439
|
};
|
|
404
440
|
}
|