@lystech/core 1.0.1

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 ADDED
@@ -0,0 +1,2 @@
1
+
2
+ <!-- Test auto-publish workflow - 2026-04-03 14:19:11 -->
package/bin/README.md ADDED
@@ -0,0 +1,126 @@
1
+ # 📦 Scripts LystechCoreNpmPackage
2
+
3
+ ## Commandes Disponibles
4
+
5
+ ### 🔗 `npx lystechcorenpmpackage attach`
6
+
7
+ **Attache votre projet au système de mise à jour automatique.**
8
+
9
+ ```bash
10
+ npx lystechcorenpmpackage attach
11
+ ```
12
+
13
+ **Ce que ça fait:**
14
+
15
+ - Détecte automatiquement votre repo GitHub
16
+ - Génère la configuration pour `consumers.json`
17
+ - Guide pour compléter le setup (PR, secrets, etc.)
18
+
19
+ **Fichier**: `bin/attach.cjs`
20
+
21
+ ---
22
+
23
+ ### ⚙️ `npx lystechcorenpmpackage lystech-auto-update-init` (Legacy)
24
+
25
+ **Crée un workflow optionnel de fallback dans votre projet.**
26
+
27
+ ```bash
28
+ npx lystechcorenpmpackage lystech-auto-update-init [--force]
29
+ ```
30
+
31
+ **Options:**
32
+
33
+ - `--force`: Écrase le workflow existant
34
+ - `--dry-run`: Affiche le YAML sans créer de fichier
35
+ - `--package=<name>`: Nom du package à surveiller
36
+ - `--deploy-script=<script>`: Script de déploiement custom
37
+
38
+ **Note**: Ce workflow n'est plus nécessaire avec le nouveau système centralisé, mais peut servir de fallback manuel.
39
+
40
+ **Fichier**: `bin/setup-github-action.cjs`
41
+
42
+ ---
43
+
44
+ ### 🔍 `npx lystechcorenpmpackage check-pwa`
45
+
46
+ **Vérifie la configuration PWA de votre projet.**
47
+
48
+ ```bash
49
+ npx lystechcorenpmpackage check-pwa
50
+ ```
51
+
52
+ **Fichier**: `bin/check-pwa.cjs`
53
+
54
+ ---
55
+
56
+ ## 🚀 Workflow Recommandé pour Nouveaux Projets
57
+
58
+ ```bash
59
+ # 1. Installer le package
60
+ npm install lystechcorenpmpackage
61
+
62
+ # 2. Attacher au système de mise à jour
63
+ npx lystechcorenpmpackage attach
64
+
65
+ # 3. Suivre les instructions affichées
66
+
67
+ # ✅ Terminé!
68
+ ```
69
+
70
+ ---
71
+
72
+ ## 🔧 Pour les Développeurs du Package
73
+
74
+ ### Structure
75
+
76
+ ```
77
+ bin/
78
+ ├── attach.cjs # Commande principale d'attachement
79
+ ├── setup-github-action.cjs # (Legacy) Génération de workflow local
80
+ ├── check-pwa.cjs # Vérification PWA
81
+ ├── notify-consumers.cjs # (Legacy) Notification manuelle
82
+ └── README.md # Ce fichier
83
+ ```
84
+
85
+ ### Ajouter une Nouvelle Commande
86
+
87
+ 1. Créer le fichier dans `bin/`
88
+ 2. Ajouter le shebang: `#!/usr/bin/env node`
89
+ 3. Rendre exécutable: `chmod +x bin/nouvelle-commande.cjs`
90
+ 4. Ajouter dans `package.json` → `bin`:
91
+ ```json
92
+ {
93
+ "bin": {
94
+ "nouvelle-commande": "./bin/nouvelle-commande.cjs"
95
+ }
96
+ }
97
+ ```
98
+
99
+ ### Tester Localement
100
+
101
+ ```bash
102
+ # Depuis le package
103
+ node bin/attach.cjs
104
+
105
+ # Ou depuis n'importe où
106
+ npm link
107
+ npx lystechcorenpmpackage attach
108
+ npm unlink
109
+ ```
110
+
111
+ ---
112
+
113
+ ## 📚 Documentation
114
+
115
+ - [Guide d'attachement](../ATTACH-GUIDE.md) - Guide utilisateur pour `attach`
116
+ - [Guide Auto-Update complet](../AUTO-UPDATE-GUIDE.md) - Documentation complète du système
117
+ - [consumers.json](../consumers.json) - Configuration des projets
118
+
119
+ ---
120
+
121
+ ## 🆘 Support
122
+
123
+ Pour toute question ou problème:
124
+
125
+ - 📖 Lire la documentation ci-dessus
126
+ - 🐛 [Créer une issue](https://github.com/eracine4/lystechcorenpmpackage/issues)
package/bin/attach.cjs ADDED
@@ -0,0 +1,277 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Script pour attacher un projet au système de mise à jour automatique
5
+ *
6
+ * Usage: npx lystechcorenpmpackage attach
7
+ *
8
+ * Ce script:
9
+ * 1. Détecte le repo GitHub actuel
10
+ * 2. Génère la configuration pour consumers.json
11
+ * 3. Guide l'utilisateur pour compléter le setup
12
+ */
13
+
14
+ const fs = require("fs");
15
+ const path = require("path");
16
+ const { execSync } = require("child_process");
17
+
18
+ // Couleurs console
19
+ const colors = {
20
+ reset: "\x1b[0m",
21
+ bright: "\x1b[1m",
22
+ green: "\x1b[32m",
23
+ yellow: "\x1b[33m",
24
+ blue: "\x1b[34m",
25
+ cyan: "\x1b[36m",
26
+ red: "\x1b[31m",
27
+ };
28
+
29
+ function log(message, color = colors.reset) {
30
+ console.log(`${color}${message}${colors.reset}`);
31
+ }
32
+
33
+ function header(message) {
34
+ console.log("");
35
+ log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`, colors.cyan);
36
+ log(` ${message}`, colors.bright + colors.cyan);
37
+ log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`, colors.cyan);
38
+ console.log("");
39
+ }
40
+
41
+ function success(message) {
42
+ log(`✅ ${message}`, colors.green);
43
+ }
44
+
45
+ function warning(message) {
46
+ log(`⚠️ ${message}`, colors.yellow);
47
+ }
48
+
49
+ function error(message) {
50
+ log(`❌ ${message}`, colors.red);
51
+ }
52
+
53
+ function info(message) {
54
+ log(`ℹ️ ${message}`, colors.blue);
55
+ }
56
+
57
+ /**
58
+ * Détecte les informations Git du repo actuel
59
+ */
60
+ function detectGitInfo() {
61
+ try {
62
+ // Vérifier si on est dans un repo git
63
+ execSync("git rev-parse --git-dir", { stdio: "ignore" });
64
+
65
+ // Récupérer l'URL remote
66
+ const remoteUrl = execSync("git config --get remote.origin.url", {
67
+ encoding: "utf8",
68
+ }).trim();
69
+
70
+ // Parser l'URL GitHub
71
+ const match = remoteUrl.match(/github\.com[:/]([^/]+)\/([^/\.]+)/);
72
+ if (!match) {
73
+ return null;
74
+ }
75
+
76
+ const [, owner, repo] = match;
77
+
78
+ // Récupérer la branche par défaut
79
+ let defaultBranch = "master";
80
+ try {
81
+ defaultBranch = execSync(
82
+ "git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@'",
83
+ { encoding: "utf8", shell: "bash" },
84
+ ).trim();
85
+ } catch {
86
+ // Essayer une autre méthode
87
+ try {
88
+ defaultBranch =
89
+ execSync("git branch -r", { encoding: "utf8" })
90
+ .split("\n")
91
+ .find((b) => b.includes("HEAD"))
92
+ ?.split("->")[1]
93
+ ?.trim()
94
+ ?.replace("origin/", "") || "master";
95
+ } catch {
96
+ // Garder master par défaut
97
+ }
98
+ }
99
+
100
+ return { owner, repo, branch: defaultBranch };
101
+ } catch {
102
+ return null;
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Lit le package.json du projet
108
+ */
109
+ function readPackageJson() {
110
+ const packageJsonPath = path.join(process.cwd(), "package.json");
111
+ if (!fs.existsSync(packageJsonPath)) {
112
+ return null;
113
+ }
114
+ return JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
115
+ }
116
+
117
+ /**
118
+ * Génère la configuration pour consumers.json
119
+ */
120
+ function generateConsumerConfig(gitInfo, packageJson) {
121
+ const scripts = packageJson?.scripts || {};
122
+
123
+ return {
124
+ owner: gitInfo.owner,
125
+ repo: gitInfo.repo,
126
+ branch: gitInfo.branch,
127
+ enabled: true,
128
+ buildScript: scripts.build ? "build" : "",
129
+ deployScript: scripts.deploy ? "deploy" : "",
130
+ deployTarget: scripts.deploy?.includes("firebase")
131
+ ? "firebase"
132
+ : scripts.deploy?.includes("vercel")
133
+ ? "vercel"
134
+ : "custom",
135
+ notes: packageJson?.description || `Projet ${gitInfo.repo}`,
136
+ };
137
+ }
138
+
139
+ /**
140
+ * Affiche les instructions pour compléter le setup
141
+ */
142
+ function printInstructions(config) {
143
+ header("📋 Configuration générée");
144
+
145
+ log(
146
+ "Ajoutez cette entrée au fichier consumers.json du package:",
147
+ colors.bright,
148
+ );
149
+ console.log("");
150
+ console.log(JSON.stringify(config, null, 2));
151
+ console.log("");
152
+
153
+ header("🚀 Prochaines étapes");
154
+
155
+ log("Pour activer la mise à jour automatique:", colors.bright);
156
+ console.log("");
157
+
158
+ log(
159
+ "1️⃣ Créer une Pull Request sur le repo lystechcorenpmpackage:",
160
+ colors.cyan,
161
+ );
162
+ console.log(" - Ouvrir: https://github.com/eracine4/lystechcorenpmpackage");
163
+ console.log(" - Éditer: consumers.json");
164
+ console.log(" - Ajouter la configuration ci-dessus");
165
+ console.log("");
166
+
167
+ log("2️⃣ Configurer le token GitHub (dans le repo du package):", colors.cyan);
168
+ console.log(" Si ce n'est pas déjà fait:");
169
+ console.log(" a) Créer un Personal Access Token:");
170
+ console.log(
171
+ " https://github.com/settings/tokens/new?scopes=repo&description=Lystech%20Auto%20Update",
172
+ );
173
+ console.log(" b) Ajouter le secret CONSUMER_UPDATE_TOKEN:");
174
+ console.log(
175
+ " https://github.com/eracine4/lystechcorenpmpackage/settings/secrets/actions",
176
+ );
177
+ console.log("");
178
+
179
+ if (config.deployScript) {
180
+ log(
181
+ `3️⃣ Configurer les secrets de déploiement (${config.deployTarget}):`,
182
+ colors.cyan,
183
+ );
184
+ console.log(
185
+ ` Dans votre repo: https://github.com/${config.owner}/${config.repo}/settings/secrets/actions`,
186
+ );
187
+
188
+ if (config.deployTarget === "firebase") {
189
+ console.log(" - FIREBASE_TOKEN (requis pour npm run deploy)");
190
+ } else if (config.deployTarget === "vercel") {
191
+ console.log(" - VERCEL_TOKEN");
192
+ }
193
+ console.log("");
194
+ }
195
+
196
+ log(
197
+ "✅ Une fois la PR mergée, vos updates seront automatiques!",
198
+ colors.green,
199
+ );
200
+ console.log("");
201
+ info(
202
+ "Le package mettra à jour ce projet automatiquement à chaque publication.",
203
+ );
204
+ }
205
+
206
+ /**
207
+ * Crée un fichier de référence local
208
+ */
209
+ function createLocalReference(config) {
210
+ const refPath = path.join(process.cwd(), ".lystech-auto-update.json");
211
+ fs.writeFileSync(refPath, JSON.stringify(config, null, 2));
212
+ success(`Configuration sauvegardée dans: .lystech-auto-update.json`);
213
+ warning(
214
+ "Ajoutez ce fichier au .gitignore si vous ne voulez pas le committer",
215
+ );
216
+ }
217
+
218
+ /**
219
+ * Main
220
+ */
221
+ function main() {
222
+ header("🔗 Lystech Auto-Update - Attachement");
223
+
224
+ // Détecter le repo
225
+ const gitInfo = detectGitInfo();
226
+ if (!gitInfo) {
227
+ error("Impossible de détecter les informations Git");
228
+ console.log("Assurez-vous d'être dans un repo GitHub cloné");
229
+ process.exit(1);
230
+ }
231
+
232
+ success(
233
+ `Repo détecté: ${gitInfo.owner}/${gitInfo.repo} (branche: ${gitInfo.branch})`,
234
+ );
235
+
236
+ // Lire package.json
237
+ const packageJson = readPackageJson();
238
+ if (!packageJson) {
239
+ error("package.json introuvable");
240
+ process.exit(1);
241
+ }
242
+
243
+ success(`Projet: ${packageJson.name || gitInfo.repo}`);
244
+
245
+ // Vérifier si le package est installé
246
+ const hasPackage =
247
+ packageJson.dependencies?.lystechcorenpmpackage ||
248
+ packageJson.devDependencies?.lystechcorenpmpackage;
249
+
250
+ if (!hasPackage) {
251
+ warning("lystechcorenpmpackage n'est pas dans les dépendances");
252
+ console.log("Installez-le d'abord: npm install lystechcorenpmpackage");
253
+ console.log("");
254
+ }
255
+
256
+ // Générer la config
257
+ const config = generateConsumerConfig(gitInfo, packageJson);
258
+
259
+ // Sauvegarder localement
260
+ createLocalReference(config);
261
+
262
+ // Afficher les instructions
263
+ printInstructions(config);
264
+ }
265
+
266
+ // Point d'entrée
267
+ if (require.main === module) {
268
+ try {
269
+ main();
270
+ } catch (err) {
271
+ error(`Erreur: ${err.message}`);
272
+ console.error(err);
273
+ process.exit(1);
274
+ }
275
+ }
276
+
277
+ module.exports = { detectGitInfo, generateConsumerConfig };
@@ -0,0 +1,277 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Script universel de vérification PWA pour un projet Node.js (CommonJS)
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+
7
+ function findFileUpwards(filename, startDir = process.cwd()) {
8
+ let dir = startDir;
9
+ while (dir !== path.parse(dir).root) {
10
+ const candidate = path.join(dir, filename);
11
+ if (fs.existsSync(candidate)) return candidate;
12
+ dir = path.dirname(dir);
13
+ }
14
+ return null;
15
+ }
16
+
17
+ function checkManifest(autoCreate = false) {
18
+ const manifestPaths = [
19
+ findFileUpwards("public/manifest.json"),
20
+ findFileUpwards("manifest.json"),
21
+ ].filter(Boolean);
22
+ const defaultManifest = {
23
+ name: "Lystech Core",
24
+ short_name: "Lystech",
25
+ start_url: ".",
26
+ display: "standalone",
27
+ background_color: "#ffffff",
28
+ theme_color: "#000000",
29
+ icons: [
30
+ {
31
+ src: "/logo.png",
32
+ sizes: "192x192",
33
+ type: "image/png",
34
+ },
35
+ {
36
+ src: "/logo.png",
37
+ sizes: "512x512",
38
+ type: "image/png",
39
+ },
40
+ ],
41
+ };
42
+ let manifestPath = manifestPaths[0];
43
+ if (!manifestPath && autoCreate) {
44
+ const publicDir = findFileUpwards("public") || process.cwd();
45
+ manifestPath = fs.existsSync(path.join(publicDir, "public"))
46
+ ? path.join(publicDir, "public", "manifest.json")
47
+ : path.join(publicDir, "manifest.json");
48
+ fs.writeFileSync(manifestPath, JSON.stringify(defaultManifest, null, 2));
49
+ console.log("🟢 manifest.json créé :", manifestPath);
50
+ return manifestPath;
51
+ }
52
+ if (manifestPath) {
53
+ let content;
54
+ try {
55
+ content = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
56
+ } catch (e) {
57
+ if (autoCreate) {
58
+ fs.writeFileSync(
59
+ manifestPath,
60
+ JSON.stringify(defaultManifest, null, 2)
61
+ );
62
+ console.log("🟢 manifest.json réparé :", manifestPath);
63
+ return manifestPath;
64
+ } else {
65
+ console.error("❌ manifest.json illisible :", manifestPath);
66
+ return false;
67
+ }
68
+ }
69
+ let changed = false;
70
+ for (const key of Object.keys(defaultManifest)) {
71
+ if (!(key in content)) {
72
+ content[key] = defaultManifest[key];
73
+ changed = true;
74
+ console.log(`🟢 Champ ajouté à manifest.json : ${key}`);
75
+ }
76
+ }
77
+ if (changed && autoCreate) {
78
+ fs.writeFileSync(manifestPath, JSON.stringify(content, null, 2));
79
+ console.log("🟢 manifest.json mis à jour :", manifestPath);
80
+ } else {
81
+ console.log("✅ manifest.json trouvé :", manifestPath);
82
+ }
83
+ return manifestPath;
84
+ }
85
+ console.error(
86
+ "❌ Aucun manifest.json trouvé (ni dans public/, ni à la racine)"
87
+ );
88
+ return false;
89
+ }
90
+
91
+ function checkServiceWorker(autoCreate = false) {
92
+ const swPaths = [
93
+ findFileUpwards("public/service-worker.js"),
94
+ findFileUpwards("service-worker.js"),
95
+ ].filter(Boolean);
96
+ const requiredFunctions = {
97
+ install: `self.addEventListener("install", (event) => {
98
+ self.skipWaiting();
99
+ });`,
100
+ activate: `self.addEventListener("activate", (event) => {
101
+ event.waitUntil(self.clients.claim());
102
+ });`,
103
+ push: `self.addEventListener("push", (event) => {
104
+ const data = event.data ? event.data.json() : {};
105
+ const title = data.title || "Nouvelle notification";
106
+ const options = {
107
+ body: data.body || "Vous avez une nouvelle notification.",
108
+ icon: data.icon || "https://placehold.co/192x192/000000/FFFFFF?text=PUSH",
109
+ badge: data.badge || "https://placehold.co/72x72/000000/FFFFFF?text=BADGE",
110
+ image: data.image,
111
+ data: {
112
+ url: data.data?.url || "/",
113
+ },
114
+ actions: data.actions || [],
115
+ vibrate: [200, 100, 200],
116
+ };
117
+ event.waitUntil(self.registration.showNotification(title, options));
118
+ });`,
119
+ notificationclick: `self.addEventListener("notificationclick", (event) => {
120
+ event.notification.close();
121
+ const clickedNotification = event.notification;
122
+ const urlToOpen = clickedNotification.data.url;
123
+ event.waitUntil(
124
+ self.clients.matchAll({ type: "window" }).then((clientList) => {
125
+ for (const client of clientList) {
126
+ if (client.url === urlToOpen && "focus" in client) {
127
+ return client.focus();
128
+ }
129
+ }
130
+ if (self.clients.openWindow) {
131
+ return self.clients.openWindow(urlToOpen);
132
+ }
133
+ })
134
+ );
135
+ });`,
136
+ };
137
+ let swPath = swPaths[0];
138
+ if (!swPath && autoCreate) {
139
+ const publicDir = findFileUpwards("public") || process.cwd();
140
+ swPath = fs.existsSync(path.join(publicDir, "public"))
141
+ ? path.join(publicDir, "public", "service-worker.js")
142
+ : path.join(publicDir, "service-worker.js");
143
+ const swContent = Object.values(requiredFunctions).join("\n\n");
144
+ fs.writeFileSync(swPath, swContent);
145
+ console.log("🟢 service-worker.js créé :", swPath);
146
+ return swPath;
147
+ }
148
+ if (swPath) {
149
+ let content = fs.readFileSync(swPath, "utf8");
150
+ let changed = false;
151
+ function escapeRegExp(str) {
152
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
153
+ }
154
+ for (const fn of Object.values(requiredFunctions)) {
155
+ const signature = fn.split("\n")[0].trim();
156
+ // On veut matcher jusqu'à la fermeture de l'accolade et du parenthèse, peu importe les espaces
157
+ const regex = new RegExp(
158
+ escapeRegExp(signature) + "[\\s\\S]*?\\}s*\\);",
159
+ "gm"
160
+ );
161
+ if (regex.test(content)) {
162
+ // Remplacer la fonction existante par la version canonique
163
+ content = content.replace(regex, fn);
164
+ changed = true;
165
+ console.log(`🟢 Fonction remplacée : ${signature}`);
166
+ } else {
167
+ // Ajouter la fonction manquante
168
+ content += "\n\n" + fn;
169
+ changed = true;
170
+ console.log(`🟢 Fonction ajoutée : ${signature}`);
171
+ }
172
+ }
173
+ if (changed && autoCreate) {
174
+ fs.writeFileSync(swPath, content.trim() + "\n");
175
+ console.log("🟢 service-worker.js mis à jour :", swPath);
176
+ } else {
177
+ console.log("✅ service-worker.js trouvé :", swPath);
178
+ }
179
+ return swPath;
180
+ }
181
+ console.error(
182
+ "❌ Aucun service-worker.js trouvé (ni dans public/, ni à la racine)"
183
+ );
184
+ return false;
185
+ }
186
+
187
+ function checkIndexHtmlForManifestAndAppleTags(autoCreate = false) {
188
+ const indexPaths = [
189
+ findFileUpwards("public/index.html"),
190
+ findFileUpwards("index.html"),
191
+ ].filter(Boolean);
192
+ if (indexPaths.length === 0) {
193
+ console.error(
194
+ "❌ Aucun index.html trouvé (ni dans public/, ni à la racine)"
195
+ );
196
+ return false;
197
+ }
198
+ const indexPath = indexPaths[0];
199
+ let lines = fs.readFileSync(indexPath, "utf8").split(/\r?\n/);
200
+ let ok = true;
201
+ const requiredLines = [
202
+ '<link rel="manifest" href="/manifest.json" />',
203
+ '<meta name="apple-mobile-web-app-capable" content="yes" />',
204
+ '<meta name="apple-mobile-web-app-status-bar-style" content="default" />',
205
+ '<meta name="apple-mobile-web-app-title" content="Lystech Core" />',
206
+ '<link rel="apple-touch-icon" href="/logo.png" />',
207
+ ];
208
+ let changed = false;
209
+ for (const tag of requiredLines) {
210
+ if (lines.some((l) => l.includes(tag.replace(/\s*\/?>$/, "")))) {
211
+ console.log(`✅ ${tag} trouvé dans`, indexPath);
212
+ } else {
213
+ ok = false;
214
+ if (autoCreate) {
215
+ // Ajoute la ligne avant </head>
216
+ const headIdx = lines.findIndex((l) => l.match(/<\/head>/i));
217
+ if (headIdx !== -1) {
218
+ lines.splice(headIdx, 0, tag);
219
+ changed = true;
220
+ console.log(`🟢 ${tag} ajouté dans`, indexPath);
221
+ }
222
+ } else {
223
+ console.error(`❌ ${tag} manquant dans`, indexPath);
224
+ }
225
+ }
226
+ }
227
+ if (changed && autoCreate) {
228
+ fs.writeFileSync(indexPath, lines.join("\n"));
229
+ ok = true;
230
+ }
231
+ return ok;
232
+ }
233
+
234
+ function main() {
235
+ console.log("--- Vérification Progressive Web App ---");
236
+ const autoCreate =
237
+ process.argv.includes("--fix") || process.argv.includes("--create");
238
+ const manifest = checkManifest(autoCreate);
239
+ const serviceWorker = checkServiceWorker(autoCreate);
240
+ const indexHasManifestAndApple =
241
+ checkIndexHtmlForManifestAndAppleTags(autoCreate);
242
+
243
+ // Ajout automatique du script check-pwa dans package.json si absent
244
+ const pkgPath = findFileUpwards("package.json");
245
+ if (pkgPath) {
246
+ try {
247
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
248
+ if (!pkg.scripts) pkg.scripts = {};
249
+ if (!pkg.scripts["check-pwa"]) {
250
+ pkg.scripts["check-pwa"] = "npx lystechcorenpmpackage check-pwa --fix";
251
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
252
+ console.log("🟢 Script 'check-pwa' ajouté dans package.json");
253
+ } else {
254
+ console.log("✅ Script 'check-pwa' déjà présent dans package.json");
255
+ }
256
+ } catch (e) {
257
+ console.error(
258
+ "❌ Erreur lors de la mise à jour du package.json :",
259
+ e.message
260
+ );
261
+ }
262
+ }
263
+ if (manifest && serviceWorker && indexHasManifestAndApple) {
264
+ console.log("🎉 Votre projet est prêt pour la Progressive Web App!");
265
+ process.exit(0);
266
+ } else {
267
+ if (!manifest && autoCreate)
268
+ console.error("Impossible de créer/mettre à jour manifest.json");
269
+ if (!serviceWorker && autoCreate)
270
+ console.error("Impossible de créer/mettre à jour service-worker.js");
271
+ process.exit(1);
272
+ }
273
+ }
274
+
275
+ if (require.main === module) {
276
+ main();
277
+ }