create-byan-agent 2.6.0 → 2.6.2
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/README.md +9 -2
- package/install/bin/create-byan-agent-v2.js +231 -1
- package/install/templates/.github/agents/bmad-agent-jimmy.md +15 -0
- package/install/templates/.github/agents/bmad-agent-mike.md +15 -0
- package/install/templates/_byan/agents/jimmy.md +1293 -0
- package/install/templates/_byan/agents/mike.md +1187 -0
- package/package.json +4 -3
- package/update-byan-agent/README.md +165 -0
- package/update-byan-agent/bin/update-byan-agent.js +303 -0
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-byan-agent",
|
|
3
|
-
"version": "2.6.
|
|
4
|
-
"description": "BYAN v2.6.
|
|
3
|
+
"version": "2.6.2",
|
|
4
|
+
"description": "BYAN v2.6.1 - Intelligent AI agent creator with ELO trust system + scientific fact-check + Hermes universal dispatcher. Multi-platform (Copilot CLI, Claude Code, Codex). Merise Agile + TDD + 64 Mantras. ~54% LLM cost savings.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"create-byan-agent": "./install/bin/create-byan-agent-v2.js",
|
|
8
|
-
"byan-v2": "./install/bin/create-byan-agent-v2.js"
|
|
8
|
+
"byan-v2": "./install/bin/create-byan-agent-v2.js",
|
|
9
|
+
"update-byan-agent": "./update-byan-agent/bin/update-byan-agent.js"
|
|
9
10
|
},
|
|
10
11
|
"scripts": {
|
|
11
12
|
"test": "jest",
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# BYAN Update Agent
|
|
2
|
+
|
|
3
|
+
Mécanisme de mise à jour fonctionnel pour BYAN installé via `npx create-byan-agent`.
|
|
4
|
+
|
|
5
|
+
## Problème Résolu
|
|
6
|
+
|
|
7
|
+
Les utilisateurs qui ont installé BYAN avec une version antérieure n'avaient aucun moyen de mettre à jour leurs fichiers `_byan/` lorsqu'une nouvelle version était publiée sur npm.
|
|
8
|
+
|
|
9
|
+
## Fonctionnalités
|
|
10
|
+
|
|
11
|
+
### 1. Vérification de Version
|
|
12
|
+
```bash
|
|
13
|
+
npx create-byan-agent check
|
|
14
|
+
# ou
|
|
15
|
+
npx update-byan-agent check
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Affiche :
|
|
19
|
+
- Version actuelle (depuis `_byan/bmb/config.yaml`)
|
|
20
|
+
- Dernière version npm (depuis registry.npmjs.org)
|
|
21
|
+
- Statut : à jour / mise à jour disponible / version dev
|
|
22
|
+
|
|
23
|
+
### 2. Mise à Jour
|
|
24
|
+
```bash
|
|
25
|
+
npx create-byan-agent update
|
|
26
|
+
# ou
|
|
27
|
+
npx update-byan-agent update
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Processus :
|
|
31
|
+
1. Vérifie la version actuelle vs npm
|
|
32
|
+
2. Demande confirmation
|
|
33
|
+
3. Détecte les personnalisations
|
|
34
|
+
4. Crée un backup automatique
|
|
35
|
+
5. Télécharge la dernière version
|
|
36
|
+
6. Préserve les fichiers utilisateur :
|
|
37
|
+
- `_byan/bmb/config.yaml`
|
|
38
|
+
- `_byan/_memory/`
|
|
39
|
+
- `_byan-output/`
|
|
40
|
+
7. Restaure les personnalisations
|
|
41
|
+
8. Met à jour `byan_version` dans config.yaml
|
|
42
|
+
|
|
43
|
+
Options :
|
|
44
|
+
- `--dry-run` : Analyse sans appliquer
|
|
45
|
+
- `--force` : Forcer même si déjà à jour
|
|
46
|
+
|
|
47
|
+
### 3. Backup Manuel
|
|
48
|
+
```bash
|
|
49
|
+
npx update-byan-agent backup
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Crée un backup horodaté dans `_byan.backup/backup-YYYY-MM-DD_HH-MM-SS/`
|
|
53
|
+
|
|
54
|
+
### 4. Restauration
|
|
55
|
+
```bash
|
|
56
|
+
npx create-byan-agent restore
|
|
57
|
+
# ou
|
|
58
|
+
npx update-byan-agent restore [--path /chemin/backup]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Restaure depuis le dernier backup ou un backup spécifique.
|
|
62
|
+
|
|
63
|
+
### 5. Lister Backups
|
|
64
|
+
```bash
|
|
65
|
+
npx update-byan-agent list-backups
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Affiche tous les backups disponibles avec date et taille.
|
|
69
|
+
|
|
70
|
+
## Architecture
|
|
71
|
+
|
|
72
|
+
### Modules
|
|
73
|
+
|
|
74
|
+
#### `lib/analyzer.js`
|
|
75
|
+
- `checkCurrentVersion()` : Lit `byan_version` depuis config.yaml
|
|
76
|
+
- `fetchLatestVersion()` : Récupère dernière version npm via HTTPS
|
|
77
|
+
- `compare(current, latest)` : Comparaison semver
|
|
78
|
+
- `checkVersion()` : Combine tout pour retourner `{current, latest, needsUpdate}`
|
|
79
|
+
|
|
80
|
+
#### `lib/backup.js`
|
|
81
|
+
- `create()` : Copie `_byan/` vers `_byan.backup/backup-{timestamp}/`
|
|
82
|
+
- `restore(backupPath)` : Restaure depuis backup
|
|
83
|
+
- `getLatestBackup()` : Trouve dernier backup par date
|
|
84
|
+
- `listBackups()` : Liste tous les backups avec métadonnées
|
|
85
|
+
|
|
86
|
+
#### `lib/customization-detector.js`
|
|
87
|
+
- `detectCustomizations()` : Identifie fichiers à préserver
|
|
88
|
+
- `isModified(filePath)` : Vérifie si fichier modifié récemment
|
|
89
|
+
|
|
90
|
+
#### `bin/update-byan-agent.js`
|
|
91
|
+
Commandes CLI :
|
|
92
|
+
- `check` : Vérification version
|
|
93
|
+
- `update` : Mise à jour complète
|
|
94
|
+
- `backup` : Backup manuel
|
|
95
|
+
- `restore` : Restauration
|
|
96
|
+
- `list-backups` : Lister backups
|
|
97
|
+
|
|
98
|
+
### Intégration
|
|
99
|
+
|
|
100
|
+
Le binaire principal `install/bin/create-byan-agent-v2.js` expose maintenant :
|
|
101
|
+
- `npx create-byan-agent` : Installation initiale
|
|
102
|
+
- `npx create-byan-agent check` : Vérification version
|
|
103
|
+
- `npx create-byan-agent update` : Mise à jour
|
|
104
|
+
- `npx create-byan-agent restore` : Restauration
|
|
105
|
+
|
|
106
|
+
## Sécurité
|
|
107
|
+
|
|
108
|
+
### Trust But Verify (Mantra IA-1)
|
|
109
|
+
- Validation de la version npm avant téléchargement
|
|
110
|
+
- Backup automatique avant toute modification
|
|
111
|
+
- Rollback automatique en cas d'erreur
|
|
112
|
+
- Préservation des personnalisations utilisateur
|
|
113
|
+
|
|
114
|
+
### Zero Emoji dans Code (Mantra IA-23)
|
|
115
|
+
Tous les messages utilisateur utilisent des symboles textuels.
|
|
116
|
+
|
|
117
|
+
### Dépendances
|
|
118
|
+
Utilise uniquement les modules déjà présents dans BYAN :
|
|
119
|
+
- `https` : Requêtes npm registry (built-in)
|
|
120
|
+
- `fs` / `fs-extra` : Opérations fichiers
|
|
121
|
+
- `path` : Manipulation chemins
|
|
122
|
+
- `js-yaml` : Parsing config.yaml
|
|
123
|
+
- `chalk`, `ora`, `inquirer` : UI
|
|
124
|
+
|
|
125
|
+
## Workflow Utilisateur
|
|
126
|
+
|
|
127
|
+
### Scénario Typique
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# 1. Installation initiale (v2.6.0)
|
|
131
|
+
npx create-byan-agent
|
|
132
|
+
|
|
133
|
+
# 2. Quelques semaines plus tard, nouvelle version disponible (v2.6.1)
|
|
134
|
+
npx create-byan-agent check
|
|
135
|
+
# → Affiche: Version actuelle: 2.6.0, npm: 2.6.1
|
|
136
|
+
# → Suggère: npx create-byan-agent update
|
|
137
|
+
|
|
138
|
+
# 3. Mise à jour
|
|
139
|
+
npx create-byan-agent update
|
|
140
|
+
# → Backup créé
|
|
141
|
+
# → Télécharge v2.6.1
|
|
142
|
+
# → Préserve config.yaml, _memory/, _byan-output/
|
|
143
|
+
# → Succès!
|
|
144
|
+
|
|
145
|
+
# 4. En cas de problème
|
|
146
|
+
npx create-byan-agent restore
|
|
147
|
+
# → Restaure backup automatiquement
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Mantras Applied
|
|
151
|
+
- IA-1: Trust But Verify
|
|
152
|
+
- IA-16: Challenge Before Confirm
|
|
153
|
+
- IA-23: Zero Emoji in Code
|
|
154
|
+
- #3: KISS (Keep It Simple)
|
|
155
|
+
- #4: YAGNI (You Aren't Gonna Need It)
|
|
156
|
+
- #39: Evaluate Consequences
|
|
157
|
+
|
|
158
|
+
## License
|
|
159
|
+
MIT
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
**Implémenté par:** Rachid (NPM/NPX Deployment Specialist)
|
|
164
|
+
**Version:** 1.0.0
|
|
165
|
+
**Date:** 2025-01-20
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const ora = require('ora');
|
|
6
|
+
const inquirer = require('inquirer');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const { execSync } = require('child_process');
|
|
10
|
+
|
|
11
|
+
const Analyzer = require('../lib/analyzer');
|
|
12
|
+
const Backup = require('../lib/backup');
|
|
13
|
+
const CustomizationDetector = require('../lib/customization-detector');
|
|
14
|
+
|
|
15
|
+
program
|
|
16
|
+
.name('update-byan-agent')
|
|
17
|
+
.description('Gestion des mises a jour BYAN avec detection de conflits')
|
|
18
|
+
.version('2.6.1');
|
|
19
|
+
|
|
20
|
+
program
|
|
21
|
+
.command('check')
|
|
22
|
+
.description('Verifier version actuelle vs derniere version npm')
|
|
23
|
+
.action(async () => {
|
|
24
|
+
const spinner = ora('Verification version BYAN...').start();
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const installPath = process.cwd();
|
|
28
|
+
const analyzer = new Analyzer(installPath);
|
|
29
|
+
|
|
30
|
+
const versionInfo = await analyzer.checkVersion();
|
|
31
|
+
|
|
32
|
+
spinner.succeed('Verification terminee');
|
|
33
|
+
|
|
34
|
+
console.log('');
|
|
35
|
+
console.log(chalk.bold('Informations de version:'));
|
|
36
|
+
console.log(chalk.gray(' Version actuelle: ') + chalk.cyan(versionInfo.current));
|
|
37
|
+
console.log(chalk.gray(' Version npm: ') + chalk.cyan(versionInfo.latest));
|
|
38
|
+
console.log('');
|
|
39
|
+
|
|
40
|
+
if (versionInfo.upToDate) {
|
|
41
|
+
console.log(chalk.green(' BYAN est a jour!'));
|
|
42
|
+
} else if (versionInfo.needsUpdate) {
|
|
43
|
+
console.log(chalk.yellow(' Une mise a jour est disponible'));
|
|
44
|
+
console.log(chalk.gray(' Executer: npx update-byan-agent update'));
|
|
45
|
+
} else if (versionInfo.ahead) {
|
|
46
|
+
console.log(chalk.blue(' Vous utilisez une version dev en avance sur npm'));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
} catch (error) {
|
|
50
|
+
spinner.fail('Erreur verification version');
|
|
51
|
+
console.error(chalk.red(` ${error.message}`));
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
program
|
|
57
|
+
.command('update')
|
|
58
|
+
.description('Mettre a jour installation BYAN')
|
|
59
|
+
.option('--dry-run', 'Analyser sans appliquer les changements')
|
|
60
|
+
.option('--force', 'Forcer la mise a jour meme si deja a jour')
|
|
61
|
+
.action(async (options) => {
|
|
62
|
+
const installPath = process.cwd();
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
// Step 1: Check version
|
|
66
|
+
const spinner = ora('Verification version...').start();
|
|
67
|
+
const analyzer = new Analyzer(installPath);
|
|
68
|
+
const versionInfo = await analyzer.checkVersion();
|
|
69
|
+
spinner.succeed(`Version actuelle: ${versionInfo.current}, npm: ${versionInfo.latest}`);
|
|
70
|
+
|
|
71
|
+
if (versionInfo.upToDate && !options.force) {
|
|
72
|
+
console.log(chalk.green('\nBYAN est deja a jour!'));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (options.dryRun) {
|
|
77
|
+
console.log(chalk.cyan('\nMode dry-run: Aucune modification appliquee'));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Step 2: Confirm update
|
|
82
|
+
const { confirmUpdate } = await inquirer.prompt([{
|
|
83
|
+
type: 'confirm',
|
|
84
|
+
name: 'confirmUpdate',
|
|
85
|
+
message: `Mettre a jour BYAN ${versionInfo.current} -> ${versionInfo.latest}?`,
|
|
86
|
+
default: true
|
|
87
|
+
}]);
|
|
88
|
+
|
|
89
|
+
if (!confirmUpdate) {
|
|
90
|
+
console.log(chalk.yellow('Mise a jour annulee'));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Step 3: Detect customizations
|
|
95
|
+
const detectorSpinner = ora('Detection des personnalisations...').start();
|
|
96
|
+
const detector = new CustomizationDetector(installPath);
|
|
97
|
+
const customizations = await detector.detectCustomizations();
|
|
98
|
+
detectorSpinner.succeed(`${customizations.length} fichiers a preserver detectes`);
|
|
99
|
+
|
|
100
|
+
// Step 4: Create backup
|
|
101
|
+
const backupSpinner = ora('Creation backup...').start();
|
|
102
|
+
const backup = new Backup(installPath);
|
|
103
|
+
const backupPath = await backup.create();
|
|
104
|
+
backupSpinner.succeed(`Backup cree: ${path.basename(backupPath)}`);
|
|
105
|
+
|
|
106
|
+
// Step 5: Preserve customizations
|
|
107
|
+
const preserveSpinner = ora('Sauvegarde des personnalisations...').start();
|
|
108
|
+
const tempDir = path.join(installPath, '.byan-update-temp');
|
|
109
|
+
if (fs.existsSync(tempDir)) {
|
|
110
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
111
|
+
}
|
|
112
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
113
|
+
|
|
114
|
+
for (const custom of customizations) {
|
|
115
|
+
if (fs.existsSync(custom.path)) {
|
|
116
|
+
const relativePath = path.relative(installPath, custom.path);
|
|
117
|
+
const tempPath = path.join(tempDir, relativePath);
|
|
118
|
+
const tempParent = path.dirname(tempPath);
|
|
119
|
+
|
|
120
|
+
if (!fs.existsSync(tempParent)) {
|
|
121
|
+
fs.mkdirSync(tempParent, { recursive: true });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (fs.statSync(custom.path).isDirectory()) {
|
|
125
|
+
copyRecursive(custom.path, tempPath);
|
|
126
|
+
} else {
|
|
127
|
+
fs.copyFileSync(custom.path, tempPath);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
preserveSpinner.succeed('Personnalisations sauvegardees');
|
|
132
|
+
|
|
133
|
+
// Step 6: Download and install latest version
|
|
134
|
+
const updateSpinner = ora('Telechargement derniere version...').start();
|
|
135
|
+
try {
|
|
136
|
+
// Remove current _byan directory
|
|
137
|
+
const byanDir = path.join(installPath, '_byan');
|
|
138
|
+
if (fs.existsSync(byanDir)) {
|
|
139
|
+
fs.rmSync(byanDir, { recursive: true, force: true });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Run npm install to get latest create-byan-agent
|
|
143
|
+
execSync('npm install --no-save create-byan-agent@latest', {
|
|
144
|
+
cwd: installPath,
|
|
145
|
+
stdio: 'pipe'
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Copy _byan from node_modules to project root
|
|
149
|
+
const nodeModulesByan = path.join(installPath, 'node_modules', 'create-byan-agent', '_byan');
|
|
150
|
+
if (fs.existsSync(nodeModulesByan)) {
|
|
151
|
+
copyRecursive(nodeModulesByan, byanDir);
|
|
152
|
+
} else {
|
|
153
|
+
throw new Error('_byan directory not found in npm package');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
updateSpinner.succeed('Derniere version installee');
|
|
157
|
+
} catch (error) {
|
|
158
|
+
updateSpinner.fail('Erreur installation');
|
|
159
|
+
|
|
160
|
+
// Rollback
|
|
161
|
+
const rollbackSpinner = ora('Restauration backup...').start();
|
|
162
|
+
await backup.restore(backupPath);
|
|
163
|
+
rollbackSpinner.succeed('Backup restaure');
|
|
164
|
+
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Step 7: Restore customizations
|
|
169
|
+
const restoreSpinner = ora('Restauration personnalisations...').start();
|
|
170
|
+
for (const custom of customizations) {
|
|
171
|
+
const relativePath = path.relative(installPath, custom.path);
|
|
172
|
+
const tempPath = path.join(tempDir, relativePath);
|
|
173
|
+
|
|
174
|
+
if (fs.existsSync(tempPath)) {
|
|
175
|
+
const targetParent = path.dirname(custom.path);
|
|
176
|
+
|
|
177
|
+
if (!fs.existsSync(targetParent)) {
|
|
178
|
+
fs.mkdirSync(targetParent, { recursive: true });
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (fs.statSync(tempPath).isDirectory()) {
|
|
182
|
+
copyRecursive(tempPath, custom.path);
|
|
183
|
+
} else {
|
|
184
|
+
fs.copyFileSync(tempPath, custom.path);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
restoreSpinner.succeed('Personnalisations restaurees');
|
|
189
|
+
|
|
190
|
+
// Cleanup temp directory
|
|
191
|
+
if (fs.existsSync(tempDir)) {
|
|
192
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
console.log('');
|
|
196
|
+
console.log(chalk.green.bold('Mise a jour terminee avec succes!'));
|
|
197
|
+
console.log(chalk.gray(` ${versionInfo.current} -> ${versionInfo.latest}`));
|
|
198
|
+
console.log('');
|
|
199
|
+
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.error('');
|
|
202
|
+
console.error(chalk.red.bold('Erreur lors de la mise a jour:'));
|
|
203
|
+
console.error(chalk.red(` ${error.message}`));
|
|
204
|
+
console.error('');
|
|
205
|
+
console.error(chalk.yellow('Le backup est disponible dans _byan.backup/'));
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
program
|
|
211
|
+
.command('backup')
|
|
212
|
+
.description('Creer backup manuel de _byan')
|
|
213
|
+
.action(async () => {
|
|
214
|
+
const spinner = ora('Creation backup...').start();
|
|
215
|
+
|
|
216
|
+
try {
|
|
217
|
+
const installPath = process.cwd();
|
|
218
|
+
const backup = new Backup(installPath);
|
|
219
|
+
const backupPath = await backup.create();
|
|
220
|
+
|
|
221
|
+
spinner.succeed('Backup cree avec succes');
|
|
222
|
+
console.log(chalk.gray(` Chemin: ${backupPath}`));
|
|
223
|
+
|
|
224
|
+
} catch (error) {
|
|
225
|
+
spinner.fail('Erreur creation backup');
|
|
226
|
+
console.error(chalk.red(` ${error.message}`));
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
program
|
|
232
|
+
.command('restore')
|
|
233
|
+
.description('Restaurer depuis backup')
|
|
234
|
+
.option('-p, --path <path>', 'Chemin du backup (dernier par defaut)')
|
|
235
|
+
.action(async (options) => {
|
|
236
|
+
const spinner = ora('Restauration backup...').start();
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
const installPath = process.cwd();
|
|
240
|
+
const backup = new Backup(installPath);
|
|
241
|
+
|
|
242
|
+
await backup.restore(options.path);
|
|
243
|
+
|
|
244
|
+
spinner.succeed('Backup restaure avec succes');
|
|
245
|
+
|
|
246
|
+
} catch (error) {
|
|
247
|
+
spinner.fail('Erreur restauration backup');
|
|
248
|
+
console.error(chalk.red(` ${error.message}`));
|
|
249
|
+
process.exit(1);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
program
|
|
254
|
+
.command('list-backups')
|
|
255
|
+
.description('Lister les backups disponibles')
|
|
256
|
+
.action(async () => {
|
|
257
|
+
try {
|
|
258
|
+
const installPath = process.cwd();
|
|
259
|
+
const backup = new Backup(installPath);
|
|
260
|
+
const backups = await backup.listBackups();
|
|
261
|
+
|
|
262
|
+
if (backups.length === 0) {
|
|
263
|
+
console.log(chalk.yellow('Aucun backup disponible'));
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
console.log(chalk.bold('\nBackups disponibles:'));
|
|
268
|
+
backups.forEach((b, i) => {
|
|
269
|
+
const size = (b.size / 1024).toFixed(2);
|
|
270
|
+
console.log(` ${i + 1}. ${chalk.cyan(b.name)}`);
|
|
271
|
+
console.log(` ${chalk.gray('Date:')} ${new Date(b.timestamp).toLocaleString()}`);
|
|
272
|
+
console.log(` ${chalk.gray('Taille:')} ${size} KB`);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
} catch (error) {
|
|
276
|
+
console.error(chalk.red(`Erreur: ${error.message}`));
|
|
277
|
+
process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Helper function to copy directory recursively
|
|
283
|
+
*/
|
|
284
|
+
function copyRecursive(src, dest) {
|
|
285
|
+
if (!fs.existsSync(dest)) {
|
|
286
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
290
|
+
|
|
291
|
+
for (const entry of entries) {
|
|
292
|
+
const srcPath = path.join(src, entry.name);
|
|
293
|
+
const destPath = path.join(dest, entry.name);
|
|
294
|
+
|
|
295
|
+
if (entry.isDirectory()) {
|
|
296
|
+
copyRecursive(srcPath, destPath);
|
|
297
|
+
} else {
|
|
298
|
+
fs.copyFileSync(srcPath, destPath);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
program.parse();
|