create-fleetbo-project 1.2.42 → 1.2.44

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.
@@ -11,7 +11,9 @@ const branchName = 'master';
11
11
  const archiveUrl = `https://github.com/${repoOwner}/${repoName}/archive/refs/heads/${branchName}.tar.gz`;
12
12
  const bootstrapUrl = 'https://us-central1-myapp-259bf.cloudfunctions.net/bootstrapProject';
13
13
 
14
-
14
+ // ------------------------------------------------------------------
15
+ // CONTENU DU CLI (Intégré pour génération automatique)
16
+ // ------------------------------------------------------------------
15
17
  const CLI_SCRIPT_CONTENT = `#!/usr/bin/env node
16
18
  const { spawn, execSync } = require('child_process');
17
19
  const fs = require('fs');
@@ -34,7 +36,7 @@ const command = args[0];
34
36
  process.env.DOTENV_SILENT = 'true';
35
37
  const envPath = path.join(process.cwd(), '.env');
36
38
  if (!fs.existsSync(envPath)) {
37
- console.error('\\\\x1b[31m%s\\\\x1b[0m', '❌ Error: Configuration file (.env) not found.');
39
+ console.error('\\x1b[31m%s\\x1b[0m', '❌ Error: Configuration file (.env) not found.');
38
40
  process.exit(1);
39
41
  }
40
42
  dotenv.config({ path: envPath, quiet: true });
@@ -48,19 +50,19 @@ const checkGitSecurity = () => {
48
50
  const gitignorePath = path.join(process.cwd(), '.gitignore');
49
51
  if (fs.existsSync(gitDir)) {
50
52
  if (!fs.existsSync(gitignorePath)) {
51
- console.error('\\\\n\\\\x1b[31m🚨 SECURITY ALERT:\\\\x1b[0m .git detected but no .gitignore found.');
53
+ console.error('\\n\\x1b[31m🚨 SECURITY ALERT:\\x1b[0m .git detected but no .gitignore found.');
52
54
  process.exit(1);
53
55
  }
54
56
  const gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
55
57
  if (!gitignoreContent.includes('.env')) {
56
- console.error('\\\\n\\\\x1b[31m🚨 CRITICAL RISK:\\\\x1b[0m .env is NOT ignored by Git.');
58
+ console.error('\\n\\x1b[31m🚨 CRITICAL RISK:\\x1b[0m .env is NOT ignored by Git.');
57
59
  process.exit(1);
58
60
  }
59
61
  }
60
62
  };
61
63
 
62
64
  if (!projectId) {
63
- console.error('\\\\n❌ Error: Project ID missing in .env.\\\\n');
65
+ console.error('\\n❌ Error: Project ID missing in .env.\\n');
64
66
  process.exit(1);
65
67
  }
66
68
 
@@ -73,17 +75,19 @@ const injectRouteIntoAppJs = (pageName, subPath = '') => {
73
75
 
74
76
  if (!content.includes(alexRouteAnchor)) return false;
75
77
 
76
- const pathPrefix = subPath ? \\\`\\\${subPath}/\\\` : '';
77
- const importLine = \\\`import \\\${pageName} from './pages/\\\${pathPrefix}\\\${pageName}';\\\`;
78
- const routeLine = \\\`<Route path="/\\\${pathPrefix.toLowerCase()}\\\${pageName.toLowerCase()}" element=<\\\${pageName} /> />\\\`;
78
+ // Chemin dynamique selon si c'est une page ou un mock
79
+ const pathPrefix = subPath ? \`\${subPath}/\` : '';
80
+ const importLine = \`import \${pageName} from './pages/\${pathPrefix}\${pageName}';\`;
81
+ const routeLine = \`<Route path="/\${pathPrefix.toLowerCase()}\${pageName.toLowerCase()}" element=<\${\${pageName} />} />\`;
79
82
 
80
83
  let injected = false;
81
84
  if (!content.includes(importLine)) {
82
- content = content.replace(importAnchor, \\\`\\\${importLine}\\\\n\\\${importAnchor}\\\`);
85
+ content = content.replace(importAnchor, \`\${importLine}\\n\${importAnchor}\`);
83
86
  injected = true;
84
87
  }
85
88
  if (!content.includes(routeLine)) {
86
- content = content.replace(alexRouteAnchor, \\\`\\\${routeLine}\\\\n \\\${alexRouteAnchor}\\\`);
89
+ // Injection précise dans l'ancre Alex
90
+ content = content.replace(alexRouteAnchor, \`\${routeLine}\\n \${alexRouteAnchor}\`);
87
91
  injected = true;
88
92
  }
89
93
 
@@ -95,10 +99,10 @@ const showEnergyTransfer = async () => {
95
99
  const width = 30;
96
100
  for (let i = 0; i <= width; i++) {
97
101
  const dots = "█".repeat(i); const empty = "░".repeat(width - i);
98
- process.stdout.write(\\\`\\\\r \\\\x1b[32m⚡ Alex Energy Sync:\\\\x1b[0m [\\\${dots}\\\${empty}] \\\${Math.round((i / width) * 100)}%\\\`);
102
+ process.stdout.write(\`\\r \\x1b[32m⚡ Alex Energy Sync:\\x1b[0m [\${dots}\${empty}] \${Math.round((i / width) * 100)}%\`);
99
103
  await new Promise(r => setTimeout(r, 45));
100
104
  }
101
- process.stdout.write('\\\\n');
105
+ process.stdout.write('\\n');
102
106
  };
103
107
 
104
108
  if (command === 'alex') {
@@ -106,43 +110,51 @@ if (command === 'alex') {
106
110
  const initialPrompt = args.slice(1).join(' ');
107
111
 
108
112
  const processAlexRequest = async (prompt) => {
109
- process.stdout.write('\\\\x1b[33m🧠 Alex is thinking...\\\\x1b[0m');
113
+ process.stdout.write('\\x1b[33m🧠 Alex is thinking...\\x1b[0m');
110
114
  try {
111
115
  const result = await axios.post(ALEX_ENGINE_URL, { prompt, projectType: 'android' }, {
112
116
  headers: { 'x-project-id': projectId }
113
117
  });
114
118
 
115
119
  const aiData = result.data;
116
- process.stdout.write('\\\\r' + ' '.repeat(50) + '\\\\r');
120
+ // 1. On efface "Alex is thinking..."
121
+ process.stdout.write('\\r' + ' '.repeat(50) + '\\r');
117
122
 
123
+ // --- 1. GESTION DU QUOTA (EN ROUGE) ---
118
124
  if (aiData.status === 'quota_exceeded') {
119
- console.log(\\\`\\\\n\\\\x1b[31m⛔ ENGINE OUT OF FUEL:\\\\x1b[0m \\\${aiData.message}\\\`);
125
+ console.log(\`\\n\\x1b[31m⛔ ENGINE OUT OF FUEL:\\x1b[0m \${aiData.message}\`);
120
126
  return;
121
127
  }
122
128
 
129
+ // --- 2. AFFICHAGE DE LA RÉPONSE ---
123
130
  if (aiData.status === 'success' || aiData.status === 'message') {
131
+ // ✅ AJOUT : Saut de ligne pour séparer de votre commande "username ❯"
124
132
  console.log('');
125
- console.log(\\\`\\\\x1b[32mAlex ❯\\\\x1b[0m \\\${aiData.message || "I'm ready."}\\\`);
133
+
134
+ // Alex répond en Vert
135
+ console.log(\`\\x1b[32mAlex ❯\\x1b[0m \${aiData.message || "I'm ready."}\`);
126
136
 
137
+ // Jauge d'énergie (Bleu/Vert/Rouge)
127
138
  if (aiData.remainingTokens !== undefined) {
128
139
  const remaining = aiData.remainingTokens;
129
140
  const limit = aiData.limit || 2500;
130
141
  const percent = Math.round((remaining / limit) * 100);
131
- const energyColor = percent > 30 ? '\\\\x1b[32m' : '\\\\x1b[31m';
132
- console.log(\\\`\\\\x1b[36m📊 Energy:\\\\x1b[0m \\\${energyColor}\\\${percent}%\\\\x1b[0m (\\\${remaining}/\\\${limit} tokens left)\\\`);
142
+ const energyColor = percent > 30 ? '\\x1b[32m' : '\\x1b[31m';
143
+ console.log(\`\\x1b[36m📊 Energy:\\x1b[0m \${energyColor}\${percent}%\\x1b[0m (\${remaining}/\${limit} tokens left)\`);
133
144
  }
134
145
  }
135
146
 
147
+ // --- 4. TRAITEMENT DES FICHIERS (SI PRÉSENTS) ---
136
148
  if (aiData.status === 'success' && aiData.moduleData) {
137
149
  const { fileName, code, mockFileName, mockCode, moduleName } = aiData.moduleData;
138
- console.log(\\\` \\\\x1b[90m⚙️ Architecting: \\\${moduleName}\\\\x1b[0m\\\`);
150
+ console.log(\` \\x1b[90m⚙️ Architecting: \${moduleName}\\x1b[0m\`);
139
151
 
140
152
  const writeFile = (dir, name, content) => {
141
153
  const fullPath = path.join(process.cwd(), dir);
142
154
  const filePath = path.join(fullPath, name);
143
155
  if (!fs.existsSync(fullPath)) fs.mkdirSync(fullPath, { recursive: true });
144
156
  fs.writeFileSync(filePath, content);
145
- console.log(\\\`\\\\x1b[32m[Written]\\\\x1b[0m \\\${dir}\\\${name}\\\`);
157
+ console.log(\`\\x1b[32m[Written]\\x1b[0m \${dir}\${name}\`);
146
158
  };
147
159
 
148
160
  if (code && fileName) {
@@ -155,37 +167,77 @@ if (command === 'alex') {
155
167
  writeFile('src/pages/mocks/', 'Quick.jsx', mockCode);
156
168
  }
157
169
  }
170
+
158
171
  } catch (error) {
159
- process.stdout.write('\\\\r' + ' '.repeat(50) + '\\\\r');
160
- console.error('\\\\n\\\\x1b[31m❌ Alex Error:\\\\x1b[0m ' + (error.response?.data?.message || error.message));
172
+ process.stdout.write('\\r' + ' '.repeat(50) + '\\r');
173
+ console.error('\\n\\x1b[31m❌ Alex Error:\\x1b[0m ' + (error.response?.data?.message || error.message));
161
174
  }
162
175
  };
163
176
 
164
177
  const startAlexSession = async () => {
165
- process.stdout.write('\\\\x1b[33m🛡️ Alex is checking runtime state...\\\\x1b[0m\\\\r');
166
- let attempts = 0; const maxAttempts = 5; let isReady = false;
178
+ process.stdout.write('\\x1b[33m🛡️ Alex is checking runtime state...\\x1b[0m\\r');
179
+
180
+ let attempts = 0;
181
+ const maxAttempts = 5;
182
+ let isReady = false;
183
+
167
184
  while (attempts < maxAttempts && !isReady) {
168
185
  try {
169
- const validation = await axios.post(ALEX_ENGINE_URL, { prompt: "ping", validateProject: true, checkNetwork: true }, { headers: { 'x-project-id': projectId }, timeout: 5000 });
186
+ const validation = await axios.post(ALEX_ENGINE_URL, {
187
+ prompt: "ping", validateProject: true, checkNetwork: true
188
+ }, { headers: { 'x-project-id': projectId }, timeout: 5000 });
189
+
170
190
  if (validation.data?.isRunning) { isReady = true; break; }
171
- attempts++; if (attempts < maxAttempts) await new Promise(r => setTimeout(r, 2000));
172
- } catch (error) { attempts++; await new Promise(r => setTimeout(r, 2000)); }
191
+ attempts++;
192
+ if (attempts < maxAttempts) await new Promise(r => setTimeout(r, 2000));
193
+ } catch (error) {
194
+ attempts++;
195
+ await new Promise(r => setTimeout(r, 2000));
196
+ }
173
197
  }
198
+
174
199
  if (!isReady) {
175
- console.error('\\\\n\\\\x1b[31m⚠️ ENGINE OFFLINE:\\\\x1b[0m Start Fleetbo runtime first: "npm run fleetbo" ');
200
+ console.error('\\n\\x1b[31m⚠️ ENGINE OFFLINE:\\x1b[0m Start Fleetbo runtime first: "npm run fleetbo" ');
176
201
  process.exit(1);
177
202
  }
178
- process.stdout.write(' '.repeat(60) + '\\\\r');
179
- console.log('\\\\n\\\\x1b[32m🤖 Alex is now online.\\\\x1b[0m');
180
- console.log('\\\\x1b[32mAlex ❯\\\\x1b[0m Welcome! I am Alex, your architect. What are we building today?\\\\n');
203
+
204
+ // --- INITIALISATION DE L'INTERFACE VISUELLE ---
205
+ process.stdout.write(' '.repeat(60) + '\\r'); // Efface le status de validation
206
+
207
+ // 1. Accueil Alex (Vert)
208
+ console.log('\\n\\x1b[32m🤖 Alex is now online.\\x1b[0m');
209
+ console.log('\\x1b[32mAlex ❯\\x1b[0m Welcome! I am Alex, your architect. What are we building today?');
210
+
211
+ // 2. Premier saut de ligne pour l'esthétique
212
+ console.log('');
213
+
214
+ // 3. Configuration du prompt Développeur (Bleu)
181
215
  const userName = testerEmail ? testerEmail.split('@')[0] : 'Dev';
182
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout, prompt: \\\`\\\\x1b[34m\\\${userName} ❯ \\\\x1b[0m\\\` });
216
+ const rl = readline.createInterface({
217
+ input: process.stdin,
218
+ output: process.stdout,
219
+ prompt: \`\\x1b[34m\${userName} ❯ \\x1b[0m\`
220
+ });
221
+
183
222
  rl.prompt();
223
+
184
224
  rl.on('line', async (line) => {
185
- if (['exit', 'quit'].includes(line.trim().toLowerCase())) { console.log('\\\\n\\\\x1b[90m👋 Alex session closed.\\\\x1b[0m'); rl.close(); return; }
186
- if (line.trim()) { await processAlexRequest(line.trim()); console.log(''); }
225
+ if (['exit', 'quit'].includes(line.trim().toLowerCase())) {
226
+ console.log('\\n\\x1b[90m👋 Alex session closed.\\x1b[0m');
227
+ rl.close();
228
+ return;
229
+ }
230
+
231
+ if (line.trim()) {
232
+ await processAlexRequest(line.trim());
233
+ // ✅ SAUT DE LIGNE après la réponse d'Alex
234
+ console.log('');
235
+ }
236
+
187
237
  rl.prompt();
188
- }).on('close', () => { process.exit(0); });
238
+ }).on('close', () => {
239
+ process.exit(0);
240
+ });
189
241
  };
190
242
 
191
243
  if (!initialPrompt || initialPrompt === '?') startAlexSession();
@@ -196,7 +248,7 @@ if (command === 'alex') {
196
248
  if (command === 'deploy') {
197
249
  checkGitSecurity();
198
250
  (async () => {
199
- console.log('\\\\n\\\\x1b[36m⚡ FLEETBO CLOUD ENGINE\\\\x1b[0m');
251
+ console.log('\\n\\x1b[36m⚡ FLEETBO CLOUD ENGINE\\x1b[0m');
200
252
  try {
201
253
  execSync('npm run build', { stdio: 'inherit' });
202
254
  let buildDir = fs.existsSync(path.join(process.cwd(), 'dist')) ? 'dist' : 'build';
@@ -207,30 +259,38 @@ if (command === 'deploy') {
207
259
  archive.directory(path.join(process.cwd(), buildDir), false);
208
260
  archive.finalize();
209
261
  });
210
- console.log('\\\\n📦 \\\\x1b[33mPreparing Neural Logic for Uplink...\\\\x1b[0m');
262
+ console.log('\\n📦 \\x1b[33mPreparing Neural Logic for Uplink...\\x1b[0m');
211
263
  await showEnergyTransfer();
212
264
  await axios.post(CLOUD_ENGINE_URL, zipBuffer, { headers: { 'Content-Type': 'application/zip', 'x-project-id': projectId } });
213
- console.log('\\\\n✅ \\\\x1b[1mDEPLOYMENT SUCCESSFUL\\\\x1b[0m | \\\\x1b[32mAlex ❯\\\\x1b[0m Runtime updated.');
265
+ console.log('\\n✅ \\x1b[1mDEPLOYMENT SUCCESSFUL\\x1b[0m | \\x1b[32mAlex ❯\\x1b[0m Runtime updated.');
214
266
  } catch (error) { process.exit(1); }
215
267
  })();
216
268
  return;
217
269
  }
218
270
 
271
+ // ==========================================
272
+ // 2. COMMANDE: GENERATE (Original préservé)
273
+ // ==========================================
219
274
  const GENERATOR_COMMANDS = ['page', 'g', 'generate', 'android', 'ios'];
220
275
  if (GENERATOR_COMMANDS.includes(command)) {
221
276
  try { require('./page.js'); } catch (e) { console.error(e.message); process.exit(1); }
222
277
  return;
223
278
  }
224
279
 
280
+ // ==========================================
281
+ // 3. COMMANDE: DEV / CLEANUP (Original préservé)
282
+ // ==========================================
225
283
  const NULL_DEV = process.platform === 'win32' ? '>nul 2>&1' : '2>/dev/null';
284
+
226
285
  function killProcessOnPort(port) {
227
286
  try {
228
287
  if (process.platform !== 'win32') {
229
- const pid = execSync(\\\`lsof -ti:\\\${port} \\\${NULL_DEV}\\\`).toString().trim();
230
- if (pid) execSync(\\\`kill -9 \\\${pid.split('\\\\n').join(' ')} \\\${NULL_DEV}\\\`);
288
+ const pid = execSync(\`lsof -ti:\${port} \${NULL_DEV}\`).toString().trim();
289
+ if (pid) execSync(\`kill -9 \${pid.split('\\n').join(' ')} \${NULL_DEV}\`);
231
290
  }
232
291
  } catch (e) {}
233
292
  }
293
+
234
294
  function killNetworkService() {
235
295
  try {
236
296
  const cmd = process.platform === 'win32' ? 'taskkill /IM cloudflared.exe /F' : 'pkill cloudflared';
@@ -240,10 +300,15 @@ function killNetworkService() {
240
300
 
241
301
  let isExiting = false;
242
302
  async function cleanupAndExit(code = 0) {
243
- if (isExiting) return; isExiting = true;
244
- console.log('\\\\n[Fleetbo] 🛑 Stopping environment...');
245
- try { await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl: '', tester: testerEmail }); } catch (e) {}
246
- killNetworkService(); killProcessOnPort(PORT); process.exit(code);
303
+ if (isExiting) return;
304
+ isExiting = true;
305
+ console.log('\\n[Fleetbo] 🛑 Stopping environment...');
306
+ try {
307
+ await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl: '', tester: testerEmail });
308
+ } catch (e) {}
309
+ killNetworkService();
310
+ killProcessOnPort(PORT);
311
+ process.exit(code);
247
312
  }
248
313
  process.on('SIGINT', () => cleanupAndExit(0));
249
314
  process.on('SIGTERM', () => cleanupAndExit(0));
@@ -251,37 +316,60 @@ process.on('SIGTERM', () => cleanupAndExit(0));
251
316
  async function syncFirebase(keyApp, networkUrl, testerEmail) {
252
317
  try {
253
318
  await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl, tester: testerEmail });
254
- console.log(\\\`\\\\n\\\\x1b[32m[Fleetbo]\\\\x1b[0m -------------------------------------------------------------\\\`);
255
- console.log('\\\\x1b[32m[Fleetbo] GO GO GO ! FLEETBO STUDIO IS READY \\\\x1b[0m');
256
- console.log(\\\`\\\\x1b[32m[Fleetbo] Link: https://fleetbo.io/studio/\\\${keyApp}\\\\x1b[0m\\\`);
257
- console.log('\\\\x1b[32m[Fleetbo] You can now start coding and previewing in Studio. 🚀\\\\x1b[0m\\\`);
258
- console.log(\\\`\\\\x1b[32m[Fleetbo]\\\\x1b[0m -------------------------------------------------------------\\\`);
259
- } catch (err) { console.error(\\\`[Fleetbo] ❌ Sync Error: \\\${err.message}\\\`); }
319
+
320
+ console.log(\`\\n\\x1b[32m[Fleetbo]\\x1b[0m -------------------------------------------------------------\`);
321
+ console.log('\\x1b[32m[Fleetbo] GO GO GO ! FLEETBO STUDIO IS READY \\x1b[0m');
322
+ console.log(\`\\x1b[32m[Fleetbo] Link: https://fleetbo.io/studio/\${keyApp}\\x1b[0m\`);
323
+ console.log('\\x1b[32m[Fleetbo] You can now start coding and previewing in Studio. 🚀\\x1b[0m');
324
+ console.log(\`\\x1b[32m[Fleetbo]\\x1b[0m -------------------------------------------------------------\`);
325
+ } catch (err) {
326
+ console.error(\`[Fleetbo] ❌ Sync Error: \${err.message}\`);
327
+ }
260
328
  }
261
329
 
262
330
  async function runDevEnvironment() {
263
- console.log(\\\`[Fleetbo] 🛡️ Initializing Dev Environment...\\\`);
264
- killNetworkService(); killProcessOnPort(PORT);
331
+ console.log(\`[Fleetbo] 🛡️ Initializing Dev Environment...\`);
332
+ killNetworkService();
333
+ killProcessOnPort(PORT);
334
+ if (!testerEmail) { console.error('Error: REACT_APP_TESTER_EMAIL missing'); process.exit(1); }
335
+
265
336
  const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
266
- const devServer = spawn(npmCmd, ['start'], { stdio: ['ignore', 'pipe', 'pipe'], shell: true, env: { ...process.env, BROWSER: 'none', PORT: PORT.toString() } });
267
- devServer.stdout.pipe(process.stdout); devServer.stderr.pipe(process.stderr);
337
+ const devServer = spawn(npmCmd, ['start'], {
338
+ stdio: ['ignore', 'pipe', 'pipe'],
339
+ shell: true,
340
+ env: { ...process.env, BROWSER: 'none', PORT: PORT.toString() }
341
+ });
342
+ devServer.stdout.pipe(process.stdout);
343
+ devServer.stderr.pipe(process.stderr);
344
+
268
345
  let connectionStarted = false;
269
346
  devServer.stdout.on('data', (data) => {
270
347
  const output = data.toString();
271
348
  if (!connectionStarted && (output.includes('Local:') || output.includes('Compiled successfully'))) {
272
349
  connectionStarted = true;
273
- console.log('\\\\n[Fleetbo] ---------------------------------------------------');
274
- console.log(\\\`[Fleetbo] 🔗 Establishing Secure Uplink...\\\\n[Fleetbo] 🛑 DO NOT open the Fleetbo Studio yet.\\\\n[Fleetbo] ⏳ Please wait green message...\\\\n[Fleetbo] ---------------------------------------------------\\\`);
350
+
351
+ console.log('\\n[Fleetbo] ---------------------------------------------------');
352
+ console.log(\`[Fleetbo] 🔗 Establishing Secure Uplink...\`);
353
+ console.log(\`[Fleetbo] 🛑 DO NOT open the Fleetbo Studio yet. \`);
354
+ console.log(\`[Fleetbo] ⏳ Please wait green message...\`);
355
+ console.log('[Fleetbo] ---------------------------------------------------');
356
+
275
357
  const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
276
- const uplink = spawn(npxCmd, ['cloudflared', 'tunnel', '--url', \\\`http://localhost:\\\${PORT}\\\`], { shell: true });
358
+ const uplink = spawn(npxCmd, ['cloudflared', 'tunnel', '--url', \`http://localhost:\${PORT}\`], { shell: true });
277
359
  uplink.stderr.on('data', (chunk) => {
278
- const match = chunk.toString().match(/https:\\\\/\\\\/[a-zA-Z0-9-]+\\\\.trycloudflare\\\\.com/);
360
+ const match = chunk.toString().match(/https:\\/\\/[a-zA-Z0-9-]+\\.trycloudflare\\.com/);
279
361
  if (match) syncFirebase(keyApp, match[0], testerEmail);
280
362
  });
281
363
  }
282
364
  });
283
365
  }
284
- runDevEnvironment();`;
366
+
367
+ runDevEnvironment();
368
+ `;
369
+
370
+ // ------------------------------------------------------------------
371
+ // FIN CONTENU CLI
372
+ // ------------------------------------------------------------------
285
373
 
286
374
 
287
375
  const args = process.argv.slice(2);
@@ -353,11 +441,11 @@ async function setupProject() {
353
441
  if (fs.existsSync(projectDir)) throw new Error(`Directory "${projectName}" already exists.`);
354
442
  fs.mkdirSync(projectDir);
355
443
 
356
- console.log(' [1/6] 📥 Downloading Fleetbo Core Engine...');
444
+ console.log(' [1/7] 📥 Downloading Fleetbo Core Engine...');
357
445
  const archivePath = path.join(projectDir, 'engine.tar.gz');
358
446
  await downloadEngine(archiveUrl, archivePath);
359
447
 
360
- console.log(' [2/6] 📦 Scaffolding project structure...');
448
+ console.log(' [2/7] 📦 Scaffolding project structure...');
361
449
  try {
362
450
  execSync(`tar -xf "${archivePath}" -C "${projectDir}" --strip-components=1`, { stdio: 'ignore' });
363
451
  fs.unlinkSync(archivePath);
@@ -365,11 +453,11 @@ async function setupProject() {
365
453
 
366
454
  process.chdir(projectDir);
367
455
 
368
- console.log(' [3/6] 🔑 Authenticating with Fleetbo Cloud...');
456
+ console.log(' [3/7] 🔑 Authenticating with Fleetbo Cloud...');
369
457
  const keys = await fetchProjectKeys(bootstrapTokenArg);
370
458
  if (!keys.enterpriseId) throw new Error("Invalid keys.");
371
459
 
372
- console.log(' [4.1/6] ⚙️ Configuring environment & CLI...');
460
+ console.log(' [4/7] ⚙️ Configuring environment & CLI...');
373
461
 
374
462
  // Correction indentation .env
375
463
  const envContent = `REACT_APP_FLEETBO_DB_KEY=${keys.fleetboDBKey}
@@ -381,7 +469,7 @@ async function setupProject() {
381
469
 
382
470
  fs.writeFileSync(path.join(projectDir, '.env'), envContent, 'utf8');
383
471
 
384
- console.log(' [4.2/6] 🛡️ Securing environment (adding .gitignore)...');
472
+ console.log(' [5/7] 🛡️ Securing environment (adding .gitignore)...');
385
473
  const gitignoreContent = `# Fleetbo Security\n.env\n.env.local\nnode_modules/\ndist/\nbuild/\n.DS_Store\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n`;
386
474
  fs.writeFileSync(path.join(projectDir, '.gitignore'), gitignoreContent, 'utf8');
387
475
 
@@ -390,11 +478,11 @@ async function setupProject() {
390
478
  fs.writeFileSync(path.join(scriptsDir, 'cli.js'), CLI_SCRIPT_CONTENT, 'utf8');
391
479
  try { fs.chmodSync(path.join(scriptsDir, 'cli.js'), '755'); } catch (e) {}
392
480
 
393
- console.log(' [5/6] 📚 Installing dependencies...');
481
+ console.log(' [6/7] 📚 Installing dependencies...');
394
482
  execSync('npm install', { stdio: 'inherit' });
395
483
  execSync('npm install cloudflared dotenv axios archiver --save-dev', { stdio: 'ignore' });
396
484
 
397
- console.log(' [6/6] ✨ Finalizing setup...');
485
+ console.log(' [7/7] ✨ Finalizing setup...');
398
486
  const packageJsonPath = path.join(projectDir, 'package.json');
399
487
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
400
488
  packageJson.name = projectName;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-fleetbo-project",
3
- "version": "1.2.42",
3
+ "version": "1.2.44",
4
4
  "description": "Creates a new Fleetbo project.",
5
5
  "main": "install-react-template.js",
6
6
  "bin": {