fleetbo-cockpit-cli 1.0.217 → 1.0.219

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.
Files changed (2) hide show
  1. package/cli.js +141 -235
  2. package/package.json +1 -1
package/cli.js CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // 🥷 SILENCIEUX ABSOLU : S'exécute en 0.1ms pour tuer la plomberie de NPM
4
- // \x1b[1A remonte d'une ligne, \x1b[2K efface la ligne. On le fait 4 fois pour écraser le bloc npm.
3
+ // ABSOLUTE SILENCE: Executes in 0.1ms to kill NPM plumbing
5
4
  process.stdout.write("\x1b[1A\x1b[2K".repeat(4));
6
5
  console.clear();
7
6
 
@@ -31,13 +30,13 @@ const args = process.argv.slice(2);
31
30
  const command = args[0];
32
31
 
33
32
  // ============================================
34
- // CONFIGURATION (.env du projet dev)
33
+ // CONFIGURATION (.env of dev project)
35
34
  // ============================================
36
35
  process.env.DOTENV_SILENT = 'true';
37
36
  const envPath = path.join(process.cwd(), '.env');
38
37
 
39
38
  if (!fs.existsSync(envPath)) {
40
- console.error('\x1b[31m%s\x1b[0m', '\nError: Configuration file (.env) not found.');
39
+ console.error('\x1b[31m%s\x1b[0m', 'Error: Configuration file (.env) not found.');
41
40
  console.error('\x1b[90m%s\x1b[0m', 'Make sure you are in a Fleetbo project directory.\n');
42
41
  process.exit(1);
43
42
  }
@@ -48,10 +47,9 @@ const projectId = process.env.VITE_FLEETBO_ENTERPRISE_ID;
48
47
  const keyApp = process.env.VITE_FLEETBO_KEY_APP;
49
48
  const testerEmail = process.env.VITE_FLEETBO_TESTER_EMAIL;
50
49
 
51
- // ═══════════════════════════════════════════════════════
52
- // DÉTECTION AUTOMATIQUE DU FRAMEWORK JS (React ou Vue)
53
- // Lit package.json — aucune configuration manuelle requise
54
- // ═══════════════════════════════════════════════════════
50
+ // =======================================================
51
+ // AUTOMATIC JS FRAMEWORK DETECTION (React or Vue)
52
+ // =======================================================
55
53
  const detectFramework = () => {
56
54
  try {
57
55
  const pkgPath = path.join(process.cwd(), 'package.json');
@@ -67,7 +65,7 @@ const detectFramework = () => {
67
65
  const JS_FRAMEWORK = detectFramework();
68
66
 
69
67
  if (!projectId) {
70
- console.error('\n\x1b[31mError: Project ID missing in .env.\x1b[0m\n');
68
+ console.error('\x1b[31m[Error] Project ID missing in .env.\x1b[0m\n');
71
69
  process.exit(1);
72
70
  }
73
71
 
@@ -80,25 +78,24 @@ const checkGitSecurity = () => {
80
78
  const gitignorePath = path.join(process.cwd(), '.gitignore');
81
79
  if (fs.existsSync(gitDir)) {
82
80
  if (!fs.existsSync(gitignorePath)) {
83
- console.error('\n\x1b[31m🚨 SECURITY ALERT:\x1b[0m .git detected but no .gitignore found.');
81
+ console.error('\x1b[31m[SECURITY ALERT]\x1b[0m .git detected but no .gitignore found.');
84
82
  process.exit(1);
85
83
  }
86
84
  const gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
87
85
  if (!gitignoreContent.includes('.env')) {
88
- console.error('\n\x1b[31m🚨 CRITICAL RISK:\x1b[0m .env is NOT ignored by Git.');
86
+ console.error('\x1b[31m[CRITICAL RISK]\x1b[0m .env is NOT ignored by Git.');
89
87
  process.exit(1);
90
88
  }
91
89
  }
92
90
  };
93
91
 
94
92
  const injectRouteIntoAppJs = (moduleName, subPath = '') => {
95
- // 🔍 DÉTERMINATION DU FICHIER CIBLE SELON LE FRAMEWORK
96
93
  const targetFile = JS_FRAMEWORK === 'vue'
97
- ? path.join(process.cwd(), 'src', 'router.js') // Cible Vue
98
- : path.join(process.cwd(), 'src', 'App.jsx'); // Cible React
94
+ ? path.join(process.cwd(), 'src', 'router.js')
95
+ : path.join(process.cwd(), 'src', 'App.jsx');
99
96
 
100
97
  if (!fs.existsSync(targetFile)) {
101
- console.error(` \x1b[31m[Safety Stop]\x1b[0m ${path.basename(targetFile)} missing.`);
98
+ console.error(`\x1b[31m[Safety Stop]\x1b[0m ${path.basename(targetFile)} missing.`);
102
99
  return false;
103
100
  }
104
101
 
@@ -109,12 +106,11 @@ const injectRouteIntoAppJs = (moduleName, subPath = '') => {
109
106
  : '{/* FLEETBO_DYNAMIC ROUTES */}';
110
107
 
111
108
  if (!content.includes(importAnchor) || !content.includes(routeAnchor)) {
112
- console.log(` \x1b[33m[Skipped]\x1b[0m Anchors missing in ${path.basename(targetFile)}. Manual injection required.`);
109
+ console.log(`\x1b[33m[Skipped]\x1b[0m Anchors missing in ${path.basename(targetFile)}. Manual injection required.`);
113
110
  return false;
114
111
  }
115
112
 
116
113
  const cleanSubPath = subPath ? `${subPath}/` : '';
117
- // 🟢 IMPORT UNIFIÉ — Vite résout l'extension automatiquement (React & Vue)
118
114
  const importLine = `import ${moduleName} from './app/${cleanSubPath}${moduleName}';`;
119
115
  let routeLine;
120
116
  if (JS_FRAMEWORK === 'vue') {
@@ -125,7 +121,6 @@ const injectRouteIntoAppJs = (moduleName, subPath = '') => {
125
121
 
126
122
  let modified = false;
127
123
 
128
- // 1. Injection de l'import (Capture l'indentation d'origine)
129
124
  if (!content.includes(importLine)) {
130
125
  const importMatch = content.match(new RegExp(`(\\n[ \\t]*)${importAnchor.replace(/[.*+?^${}()|[\\]\\]/g, '\\$&')}`));
131
126
  const importIndent = importMatch ? importMatch[1] : '\n';
@@ -133,7 +128,6 @@ const injectRouteIntoAppJs = (moduleName, subPath = '') => {
133
128
  modified = true;
134
129
  }
135
130
 
136
- // 2. Injection de la route (Capture l'indentation d'origine)
137
131
  if (!content.includes(routeLine)) {
138
132
  const routeMatch = content.match(new RegExp(`(\\n[ \\t]*)${routeAnchor.replace(/[.*+?^${}()|[\\]\\]/g, '\\$&')}`));
139
133
  const routeIndent = routeMatch ? routeMatch[1] : '\n';
@@ -153,45 +147,31 @@ const showEnergyTransfer = async () => {
153
147
  for (let i = 0; i <= width; i++) {
154
148
  const dots = "█".repeat(i);
155
149
  const empty = "░".repeat(width - i);
156
- process.stdout.write(`\r \x1b[32mPropulsion Sync:\x1b[0m [${dots}${empty}] ${Math.round((i / width) * 100)}%`);
150
+ process.stdout.write(`\r\x1b[32m[Propulsion Sync]\x1b[0m [${dots}${empty}] ${Math.round((i / width) * 100)}%`);
157
151
  await new Promise(r => setTimeout(r, 45));
158
152
  }
159
153
  process.stdout.write('\n');
160
154
  };
161
155
 
162
- // Détecte TOUS les mots en PascalCase (ex: GuestCreator, CameraModule, Tab2)
163
156
  const extractPotentialModules = (text) => {
164
- // Regex stricte : Majuscule + minuscules + Majuscule (ex: ProfileCreator, UserConfig)
165
157
  const regex = /\b[A-Z][a-z]+[A-Z][a-zA-Z0-9_]*\b/g;
166
158
  const matches = text.match(regex) || [];
167
159
  return [...new Set(matches)];
168
160
  };
169
161
 
170
-
171
- // Sert uniquement à définir le TON du contexte envoyé à Alex
172
162
  const getContextIntent = (text) => {
173
163
  const modifierKeywords = [
174
- // 🇫🇷 FRANÇAIS (Verbes d'action purs)
175
164
  'modifier', 'modifie', 'corrige', 'ajoute', 'change', 'met a jour', 'mets à jour',
176
165
  'optimise', 'améliore', 'refactorise', 'répare', 'adapte', 'remplace',
177
-
178
- // 🇬🇧 ANGLAIS (Action verbs)
179
166
  'update', 'fix', 'edit', 'add', 'modify', 'upgrade', 'optimize',
180
167
  'improve', 'refactor', 'repair', 'adapt', 'replace', 'tweak',
181
-
182
- // 🇪🇸 ESPAGNOL (Verbos de acción)
183
168
  'modifica', 'edita', 'actualiza', 'añade', 'agrega', 'mejora',
184
169
  'optimiza', 'refactoriza', 'repara', 'adapta', 'reemplaza'
185
170
  ];
186
171
 
187
172
  const inspireKeywords = [
188
- // 🇫🇷 FRANÇAIS
189
173
  'inspire', 'base', 'comme', 'modèle', 'reference', 'reprends', 'copie', 'imite', 'basé sur',
190
-
191
- // 🇬🇧 ANGLAIS
192
174
  'based on', 'model', 'like', 'copy', 'similar', 'imitate', 'replicate',
193
-
194
- // 🇪🇸 ESPAGNOL
195
175
  'inspira', 'basado', 'como', 'modelo', 'referencia', 'copia', 'imita', 'básate'
196
176
  ];
197
177
 
@@ -205,7 +185,6 @@ const getModuleCache = async ({ projectId, moduleName }) => {
205
185
  try {
206
186
  const res = await axios.post(CACHE_URL, { projectId, moduleName });
207
187
  if (res.data && res.data.found) {
208
- // On renvoie à la fois "module" (pour un seul) et "modules" (pour la liste)
209
188
  return { found: true, module: res.data.module, modules: res.data.modules };
210
189
  }
211
190
  return { found: false };
@@ -231,7 +210,6 @@ const removeRouteFromAppJs = (moduleName) => {
231
210
 
232
211
  const originalContent = content;
233
212
 
234
- // 🟢 REGEX INTELLIGENTE — supprime l'import peu importe l'extension (.vue, .jsx, ou aucune)
235
213
  const importRegex = new RegExp(
236
214
  `import\\s+${moduleName}\\s+from\\s+['"]\\./app/mocks/${moduleName}(?:\\.jsx|\\.vue)?['"];?\\n?`,
237
215
  'g'
@@ -243,13 +221,12 @@ const removeRouteFromAppJs = (moduleName) => {
243
221
 
244
222
  if (content !== originalContent) {
245
223
  fs.writeFileSync(targetFile, content);
246
- console.log(` \x1b[32m[Unrouted]\x1b[0m ${moduleName} removed from ${path.basename(targetFile)}.`);
224
+ console.log(`\x1b[32m[Unrouted]\x1b[0m ${moduleName} removed from ${path.basename(targetFile)}.`);
247
225
  return true;
248
226
  }
249
227
  return false;
250
228
  };
251
229
 
252
-
253
230
  // ============================================
254
231
  // COMMAND: alex
255
232
  // ============================================
@@ -259,41 +236,36 @@ if (command === 'alex') {
259
236
 
260
237
  const processAlexRequest = async (prompt) => {
261
238
  if (prompt.length > 4000) {
262
- console.log('\n\x1b[31m[Alex Safety] Request too long (' + prompt.length + '/4000 chars).\x1b[0m');
239
+ console.log('\x1b[31m[Alex Safety] Request too long (' + prompt.length + '/4000 chars).\x1b[0m');
263
240
  return;
264
241
  }
265
242
 
266
243
  /* =====================================================================
267
- 🟢 STRICT PATCH MANUAL COMMIT INTERCEPTION 🟢
244
+ STRICT PATCH MANUAL COMMIT INTERCEPTION
268
245
  ===================================================================== */
269
246
 
270
- // 1. Strict command detection (4 words required)
271
247
  const patchMatch = prompt.match(/^patch\s+module\s+([a-zA-Z0-9_]+)\s+(android|ios)/i);
272
-
273
- // 2. Capture human errors (missing platform)
274
248
  const partialPatchMatch = prompt.match(/^patch\s+module\s+([a-zA-Z0-9_]+)$/i);
275
249
 
276
250
  if (partialPatchMatch && !patchMatch) {
277
- console.log(`\n\x1b[31mREJECTED: Ambiguous command.\x1b[0m The platform is mandatory to avoid any Metal corruption.`);
278
- console.log(`\x1b[36m Type:\x1b[0mpatch module ${partialPatchMatch[1]} android`);
279
- console.log(`\x1b[36m Or:\x1b[0mpatch module ${partialPatchMatch[1]} ios`);
251
+ console.log(`\x1b[31m[REJECTED]\x1b[0m Ambiguous command. Platform is mandatory to avoid Metal corruption.`);
252
+ console.log(`Type: patch module ${partialPatchMatch[1]} android`);
253
+ console.log(`Or: patch module ${partialPatchMatch[1]} ios`);
280
254
  return;
281
255
  }
282
256
 
283
257
  if (patchMatch) {
284
258
  const modName = patchMatch[1];
285
- const targetPlatform = patchMatch[2].toLowerCase(); // 'android' or 'ios'
259
+ const targetPlatform = patchMatch[2].toLowerCase();
286
260
 
287
- console.log(`\n\x1b[33m🛡️ Checking integrity for ${modName} (${targetPlatform.toUpperCase()})...\x1b[0m`);
261
+ console.log(`\x1b[33m[Integrity Check] Verifying ${modName} (${targetPlatform.toUpperCase()})...\x1b[0m`);
288
262
 
289
- // Cloud Verification
290
263
  const cacheRes = await getModuleCache({ projectId, moduleName: modName });
291
264
  if (!cacheRes.found) {
292
- console.log(`\x1b[31mREJECTED:\x1b[0m The module "${modName}" does not exist in the Cloud. The first draft must ALWAYS be forged by Alex.`);
265
+ console.log(`\x1b[31m[REJECTED]\x1b[0m Module "${modName}" does not exist in the Cloud. The first draft must ALWAYS be forged by Alex.`);
293
266
  return;
294
267
  }
295
268
 
296
- // Strict and absolute paths
297
269
  const nativeExt = targetPlatform === 'android' ? 'kt' : 'swift';
298
270
  const nativeFileName = `${modName}.${nativeExt}`;
299
271
  const nativePathAPI = `public/native/${targetPlatform}/${nativeFileName}`;
@@ -302,17 +274,15 @@ if (command === 'alex') {
302
274
  const mockExt = JS_FRAMEWORK === 'vue' ? 'vue' : 'jsx';
303
275
  const mockPath = path.join(process.cwd(), 'src', 'app', 'mocks', `${modName}.${mockExt}`);
304
276
 
305
- // Physical existence validation
306
277
  if (!fs.existsSync(nativePathFull)) {
307
- console.log(`\x1b[31mFATAL ERROR:\x1b[0m Target file not found on disk (${nativePathAPI}).`);
278
+ console.log(`\x1b[31m[FATAL ERROR]\x1b[0m Target file not found on disk (${nativePathAPI}).`);
308
279
  return;
309
280
  }
310
281
 
311
282
  const localNativeCode = fs.readFileSync(nativePathFull, 'utf8');
312
283
  const localMockCode = fs.existsSync(mockPath) ? fs.readFileSync(mockPath, 'utf8') : null;
313
284
 
314
- // Pushing to Cloud
315
- process.stdout.write(` \x1b[33m[Patch Sync]\x1b[0m Pushing ${targetPlatform.toUpperCase()} modifications to Cloud OS...`);
285
+ process.stdout.write(`\x1b[33m[Patch Sync]\x1b[0m Pushing ${targetPlatform.toUpperCase()} modifications to Cloud OS... `);
316
286
  try {
317
287
  await axios.post(INJECT_DEPS_URL, {
318
288
  projectId: projectId,
@@ -326,38 +296,37 @@ if (command === 'alex') {
326
296
  isPatch: true
327
297
  }
328
298
  });
329
- process.stdout.write(` \x1b[32mOK\x1b[0m\n`);
330
- console.log(`\x1b[32m SUCCESS:\x1b[0m The local version of ${nativeFileName} is now the official reference in the Cloud.`);
299
+ process.stdout.write(`\x1b[32m[OK]\x1b[0m\n`);
300
+ console.log(`\x1b[32m[SUCCESS]\x1b[0m Local version of ${nativeFileName} is now the official reference in the Cloud.`);
331
301
  } catch (err) {
332
- process.stdout.write(` \x1b[31mFAILED\x1b[0m\n`);
333
- console.error(` ⚠️ OS sync failed: ${err.message}`);
302
+ process.stdout.write(`\x1b[31m[FAILED]\x1b[0m\n`);
303
+ console.error(`\x1b[31m[Error] OS sync failed: ${err.message}\x1b[0m`);
334
304
  }
335
- return; // Final circuit breaker
305
+ return;
336
306
  }
337
- /* ===================================================================== */
338
307
 
339
- // 📋 INTERCEPTION: LIST MODULES (Multilingue)
308
+ // INTERCEPTION: LIST MODULES
340
309
  const isListingRequest = /^(liste|list|listar|lista|quels modules|montre les modules|affiche les modules|show modules|what modules|display modules|qu[eé] m[oó]dulos|muestra los m[oó]dulos|ver m[oó]dulos)/i.test(prompt);
341
310
  if (isListingRequest) {
342
- process.stdout.write(` \x1b[90m🔍 Scanning OS Cache...\x1b[0m\n`);
311
+ process.stdout.write(`\x1b[90m[Scan] Checking OS Cache...\x1b[0m\n`);
343
312
  const cacheRes = await getModuleCache({ projectId, moduleName: null });
344
313
 
345
314
  if (cacheRes.found !== false && cacheRes.modules && cacheRes.modules.length > 0) {
346
- console.log(`\n\x1b[36m FLEETBO OS MODULES (${cacheRes.modules.length}):\x1b[0m`);
315
+ console.log(`\x1b[36m[Fleetbo OS Modules] (${cacheRes.modules.length}):\x1b[0m`);
347
316
  cacheRes.modules.forEach(m => {
348
317
  const metalColor = m.platform === 'android' ? '\x1b[32m' : '\x1b[34m';
349
- console.log(` ${metalColor}■\x1b[0m \x1b[1m${m.moduleName}\x1b[0m \x1b[90m(${m.platform})\x1b[0m`);
318
+ console.log(`[${m.platform}] \x1b[1m${m.moduleName}\x1b[0m`);
350
319
  });
351
320
  } else {
352
- console.log(`\n \x1b[90mNo modules found in the infrastructure of this project.\x1b[0m`);
321
+ console.log(`\x1b[90mNo modules found in the infrastructure of this project.\x1b[0m`);
353
322
  }
354
323
  return;
355
324
  }
356
325
 
357
- console.log('\x1b[33m🧠 Alex is thinking...\x1b[0m');
326
+ console.log('\x1b[33m[Alex] Processing request...\x1b[0m');
358
327
 
359
328
  try {
360
- // --- MEMORY SYSTEM (SMART CACHE SCANNER V3 - SOUVERAINETÉ DU MÉTAL) ---
329
+ // --- MEMORY SYSTEM (SMART CACHE SCANNER V3) ---
361
330
  let contextInjection = "";
362
331
  const potentialModules = extractPotentialModules(prompt);
363
332
 
@@ -367,7 +336,6 @@ if (command === 'alex') {
367
336
  for (let modName of potentialModules) {
368
337
  let isReferenceOnly = false;
369
338
 
370
- // LE DÉTECTEUR D'INSPIRATION
371
339
  if (modName.endsWith('Ref')) {
372
340
  isReferenceOnly = true;
373
341
  modName = modName.replace('Ref', '');
@@ -376,67 +344,59 @@ if (command === 'alex') {
376
344
  modName = modName.replace('Schema', '');
377
345
  }
378
346
 
379
- process.stdout.write(` \x1b[90m Checking Alex memory for ${modName} module...\x1b[0m`);
347
+ process.stdout.write(`\x1b[90mChecking Alex memory for ${modName} module...\x1b[0m `);
380
348
  const cache = await getModuleCache({ projectId, moduleName: modName });
381
349
 
382
- // LECTURE LOCALE DU VRAI CODE KOTLIN (La Vérité Absolue)
383
350
  const localKtPath = path.join(process.cwd(), 'public', 'native', 'android', `${modName}.kt`);
384
351
  let actualMetalCode = "";
385
352
 
386
353
  if (fs.existsSync(localKtPath)) {
387
354
  actualMetalCode = fs.readFileSync(localKtPath, 'utf8');
388
355
  } else if (cache.found && cache.module.code) {
389
- actualMetalCode = cache.module.code; // Fallback sur le cache si le fichier local n'est pas trouvé
356
+ actualMetalCode = cache.module.code;
390
357
  }
391
358
 
392
359
  if (actualMetalCode) {
393
- process.stdout.write(` \x1b[32mFOUND METAL\x1b[0m\n`);
360
+ process.stdout.write(`\x1b[32m[FOUND METAL]\x1b[0m\n`);
394
361
 
395
- // Extraction des schémas mémoires (uniquement dispo dans le cache cloud)
396
362
  let memoryScript = "";
397
- if (cache.found && cache.module.dataSchema) memoryScript += `\n[SCRIPT MÉMOIRE DONNÉES]\n${cache.module.dataSchema}\n`;
398
- if (cache.found && cache.module.uiSchema) memoryScript += `\n[SCRIPT MÉMOIRE UI NATIF]\n${cache.module.uiSchema}\n`;
363
+ if (cache.found && cache.module.dataSchema) memoryScript += `\n[DATA MEMORY SCRIPT]\n${cache.module.dataSchema}\n`;
364
+ if (cache.found && cache.module.uiSchema) memoryScript += `\n[NATIVE UI MEMORY SCRIPT]\n${cache.module.uiSchema}\n`;
399
365
 
400
- if (!memoryScript) memoryScript = `\n[SCRIPT MÉMOIRE DU MODULE ${modName}]\nAucun schéma enregistré pour ce module.\n`;
366
+ if (!memoryScript) memoryScript = `\n[MODULE MEMORY SCRIPT ${modName}]\nNo schema registered for this module.\n`;
401
367
 
402
- // 🤖 PRÉ-ANALYSE DÉTERMINISTE DU CLI (Le bouclier anti-amnésie d'Alex)
403
368
  const isTabModule = actualMetalCode.includes('action == "tab"');
404
369
  const levelWarning = isTabModule
405
- ? "\n🚨 ALERTE CRITIQUE DU SYSTÈME : Ce code natif contient 'action == \"tab\"'. Il s'agit DÉFINITIVEMENT d'un NIVEAU 5 (Fleetbo View / Sovereign Tab). Tu as l'INTERDICTION ABSOLUE de proposer Fleetbo.exec() pour ce module. Tu DOIS obligatoirement utiliser Fleetbo.openView('NomDuModule', true) dans un useEffect() pour l'intégrer, sous peine de détruire l'application.\n"
370
+ ? "\n[CRITICAL SYSTEM ALERT]: This native code contains 'action == \"tab\"'. It is DEFINITIVELY a LEVEL 5 (Fleetbo View / Sovereign Tab). You are STRICTLY FORBIDDEN to propose Fleetbo.exec() for this module. You MUST use Fleetbo.openView('ModuleName', true) in a useEffect() to integrate it, otherwise it will destroy the application.\n"
406
371
  : "";
407
372
 
408
373
  if (isReferenceOnly) {
409
- // 🚨 CAS A : INSPIRATION
410
- referenceContexts += `\n--- CONTEXTE : MODULE DE RÉFÉRENCE (${modName}) ---\nDOGME : Ne modifie pas ce module. Aligne-toi sur ses Scripts Mémoires et son Code Natif.\n${memoryScript}\n[CODE NATIF DE RÉFÉRENCE]\n${actualMetalCode}\n`;
374
+ referenceContexts += `\n--- CONTEXT: REFERENCE MODULE (${modName}) ---\nDOGMA: Do not modify this module. Align with its Memory Scripts and Native Code.\n${memoryScript}\n[REFERENCE NATIVE CODE]\n${actualMetalCode}\n`;
411
375
  } else if (!targetModuleContext) {
412
- // 🚨 CAS B : CIBLE PRINCIPALE
413
376
  const intent = getContextIntent(prompt);
414
377
  if (intent === "MODIFICATION") {
415
- targetModuleContext = `\n--- CONTEXTE : MÉTAL EXISTANT À MODIFIER (${modName}) ---\nDOGME: Tu dois modifier ce code Natif. Ensuite, tu forgeras un Mock JSX neuf basé UNIQUEMENT sur ton nouveau code Natif.${levelWarning}\n${memoryScript}\n[CODE NATIF EXISTANT]\n${actualMetalCode}\n--- FIN DU CONTEXTE ---\n`;
378
+ targetModuleContext = `\n--- CONTEXT: EXISTING NATIVE CODE TO MODIFY (${modName}) ---\nDOGMA: You must modify this Native code. Then, you will forge a new JSX Mock based SOLELY on your new Native code.${levelWarning}\n${memoryScript}\n[EXISTING NATIVE CODE]\n${actualMetalCode}\n--- END OF CONTEXT ---\n`;
416
379
  } else {
417
- targetModuleContext = `\n--- CONTEXTE : LECTURE SEULE (${modName}) ---\nPour information, voici l'état actuel du module. Ne le modifie pas, utilise-le pour répondre précisément au Pilote.${levelWarning}\n${memoryScript}\n[CODE NATIF]\n${actualMetalCode}\n`;
380
+ targetModuleContext = `\n--- CONTEXT: READ ONLY (${modName}) ---\nFor information, here is the current state of the module. Do not modify it, use it to accurately answer the Pilot.${levelWarning}\n${memoryScript}\n[NATIVE CODE]\n${actualMetalCode}\n`;
418
381
  }
419
382
  }
420
383
  } else {
421
- process.stdout.write(` \x1b[31mNOT FOUND\x1b[0m\n`);
384
+ process.stdout.write(`\x1b[31m[NOT FOUND]\x1b[0m\n`);
422
385
  }
423
386
  }
424
387
 
425
388
  contextInjection = referenceContexts + targetModuleContext;
426
389
  if (contextInjection) {
427
- prompt = contextInjection + "\n\n[INSTRUCTION DU PILOTE]\n" + prompt;
390
+ prompt = contextInjection + "\n\n[PILOT INSTRUCTION]\n" + prompt;
428
391
  }
429
- // --- END MEMORY MODIFICATION ---
430
392
 
431
- // Real-time timestamp injection
432
393
  const now = new Date();
433
- // Clean format: YYYY-MM-DD at HH:MM:SS
434
394
  const exactTime = now.toISOString().split('T')[0] + ' at ' + now.toTimeString().split(' ')[0];
435
395
 
436
- const promptWithTime = prompt + `\n\n[SYSTEM INFO: The exact current timestamp is ${exactTime}. Use it STRICTLY for your signature '// Forged by Alex on...' at the bottom of your files.]`;
396
+ const promptWithTime = prompt + `\n\n[SYSTEM INFO: The exact current timestamp is ${exactTime}. Use it STRICTLY for your signature '// Forged by Alex on...' at the bottom of your files.]`;
437
397
 
438
398
  // =================================================================
439
- // 🚀 THE AUTOMATED 3-STEP WORKFLOW (Cross-Platform)
399
+ // THE AUTOMATED 3-STEP WORKFLOW (Cross-Platform)
440
400
  // =================================================================
441
401
 
442
402
  const deepUnwrap = (raw, depth = 0) => {
@@ -476,46 +436,41 @@ if (command === 'alex') {
476
436
  return deepUnwrap(res.data);
477
437
  };
478
438
 
479
- // Fonction pour animer les étapes silencieusement
480
- const logStep = (icon, text) => {
481
- // \x1b[2K efface la ligne courante, \r ramène au début
482
- process.stdout.write(`\x1b[2K\r ${icon} ${text}`);
439
+ const logStep = (prefix, text) => {
440
+ process.stdout.write(`\x1b[2K\r${prefix} ${text}`);
483
441
  };
484
442
 
485
443
  process.stdout.write('\x1b[A\r' + ' '.repeat(50) + '\r');
486
444
 
487
- // --- ÉTAPE 1 : NATIF ---
488
- logStep('🧠', '\x1b[33m1/3 - Alex forge les fondations natives...\x1b[0m');
445
+ // --- STEP 1: NATIVE ---
446
+ logStep('[1/3]', '\x1b[33mAlex is forging native foundations...\x1b[0m');
489
447
  let aiData = await fetchStep('native_only');
490
448
 
491
449
  if (aiData.status === 'quota_exceeded') {
492
- console.log(`\n\x1b[31m ARCHITECT QUOTA REACHED:\x1b[0m ${aiData.message}`);
450
+ console.log(`\n\x1b[31m[Architect Quota Reached]:\x1b[0m ${aiData.message}`);
493
451
  return;
494
452
  }
495
453
 
496
454
  let mergedModuleData = aiData.moduleData || {};
497
455
  let aiDataMessage = aiData.message;
498
456
 
499
- // 🛡️ RÉCTROCOMPATIBILITÉ BACKEND :
500
- // Si le cloud renvoie déjà le Mock, c'est que ton index.js n'est pas encore mis à jour.
501
- // On bypass la suite pour ne pas générer de doublons et consommer du token pour rien.
502
457
  const isCloudUpdated = !mergedModuleData.mockCode;
503
458
 
504
459
  if (isCloudUpdated && mergedModuleData.code) {
505
- logStep('', '\x1b[32m1/3 - Code Natif généré.\x1b[0m\n');
460
+ logStep('[1/3]', '\x1b[32mNative code generated.\x1b[0m\n');
506
461
 
507
- // --- ÉTAPE 2 : MOCK ---
508
- logStep('🎨', '\x1b[33m2/3 - Analyse du Natif et génération de l\'Interface (Mock)...\x1b[0m');
462
+ // --- STEP 2: MOCK ---
463
+ logStep('[2/3]', '\x1b[33mAnalyzing native code and generating Interface (Mock)...\x1b[0m');
509
464
  const aiData2 = await fetchStep('mock_only', { nativeCode: mergedModuleData.code });
510
465
 
511
466
  if (aiData2.moduleData) {
512
467
  mergedModuleData.mockCode = aiData2.moduleData.mockCode;
513
468
  mergedModuleData.mockFileName = aiData2.moduleData.mockFileName;
514
469
  }
515
- logStep('', '\x1b[32m2/3 - Interface Mock générée.\x1b[0m\n');
470
+ logStep('[2/3]', '\x1b[32mInterface Mock generated.\x1b[0m\n');
516
471
 
517
- // --- ÉTAPE 3 : JSON CONFIG ---
518
- logStep('⚙️', '\x1b[33m3/3 - Finalisation de la plomberie JSON...\x1b[0m');
472
+ // --- STEP 3: JSON CONFIG ---
473
+ logStep('[3/3]', '\x1b[33mFinalizing JSON configuration...\x1b[0m');
519
474
  const aiData3 = await fetchStep('json_only', {
520
475
  nativeCode: mergedModuleData.code,
521
476
  mockCode: mergedModuleData.mockCode
@@ -526,18 +481,15 @@ if (command === 'alex') {
526
481
  mergedModuleData.dataSchema = aiData3.moduleData.dataSchema;
527
482
  mergedModuleData.uiSchema = aiData3.moduleData.uiSchema;
528
483
  }
529
- logStep('', '\x1b[32m3/3 - Configuration terminée.\x1b[0m\n');
484
+ logStep('[3/3]', '\x1b[32mConfiguration completed.\x1b[0m\n');
530
485
  } else {
531
- // Le cloud n'est pas à jour, on efface le loader de l'étape 1 en silence
532
486
  process.stdout.write(`\x1b[2K\r`);
533
487
  }
534
488
 
535
- // DISPLAY REASONING IN TERMINAL
536
489
  if (aiData.thinking_process) {
537
- console.log(` \x1b[90m🧠 Alex Analysis: ${aiData.thinking_process.substring(0, 150)}...\x1b[0m`);
490
+ console.log(`\x1b[90m[Analysis] ${aiData.thinking_process.substring(0, 150)}...\x1b[0m`);
538
491
  }
539
492
 
540
- // --- OUTPUT VERS XTERM ---
541
493
  if (aiData.status === 'success' || aiData.status === 'message' || aiData.status === 'complex_refusal') {
542
494
  let rawMsg = aiDataMessage || "I'm ready.";
543
495
  if (typeof rawMsg === 'object') {
@@ -555,7 +507,7 @@ if (command === 'alex') {
555
507
  if (moduleName.length > 40) moduleName = moduleName.substring(0, 40) + "...";
556
508
  }
557
509
 
558
- console.log(`\n \x1b[90mArchitecting: ${moduleName || 'Unknown Module'}\x1b[0m`);
510
+ console.log(`\x1b[90mArchitecting: ${moduleName || 'Unknown Module'}\x1b[0m`);
559
511
 
560
512
  const writeFile = (dir, name, content) => {
561
513
  const fullPath = path.join(process.cwd(), dir);
@@ -578,7 +530,7 @@ if (command === 'alex') {
578
530
 
579
531
  // --- KERNEL SYNCHRONIZATION ---
580
532
  const depsCount = config_offload?.dependencies?.length || 0;
581
- process.stdout.write(` \x1b[33m[OS Sync]\x1b[0m Archiving ${moduleName} to OS (${depsCount} libs)...`);
533
+ process.stdout.write(`\x1b[33m[OS Sync]\x1b[0m Archiving ${moduleName} to OS (${depsCount} libs)... `);
582
534
 
583
535
  try {
584
536
  await axios.post(INJECT_DEPS_URL, {
@@ -595,33 +547,32 @@ if (command === 'alex') {
595
547
  uiSchema: uiSchema || null
596
548
  }
597
549
  });
598
- process.stdout.write(` \x1b[32mOK\x1b[0m\n`);
550
+ process.stdout.write(`\x1b[32m[OK]\x1b[0m\n`);
599
551
  } catch (err) {
600
- process.stdout.write(` \x1b[31mFAILED\x1b[0m\n`);
601
- console.error(` ⚠️ OS sync failed: ${err.message}`);
552
+ process.stdout.write(`\x1b[31m[FAILED]\x1b[0m\n`);
553
+ console.error(`\x1b[31m[Error] OS sync failed: ${err.message}\x1b[0m`);
602
554
  }
603
555
 
604
- console.log('');
605
- console.log(`\x1b[90m If you manually edit the native code, sync it to the Cloud OS:\x1b[0m`);
606
- console.log(`\x1b[33m patch module\x1b[0m \x1b[36m${moduleName}\x1b[0m \x1b[33mandroid\x1b[0m \x1b[90m(or ios)\x1b[0m`);
607
- console.log(`\x1b[90m To eradicate this module later, open a new terminal and type:\x1b[0m`);
608
- console.log(`\x1b[31m npm run fleetbo rm\x1b[0m \x1b[36m${moduleName}\x1b[0m`);
556
+ console.log('\x1b[90mIf you manually edit the native code, sync it to the Cloud OS:\x1b[0m');
557
+ console.log(`\x1b[33mpatch module\x1b[0m \x1b[36m${moduleName}\x1b[0m \x1b[33mandroid\x1b[0m \x1b[90m(or ios)\x1b[0m`);
558
+ console.log('\x1b[90mTo eradicate this module later, open a new terminal and type:\x1b[0m');
559
+ console.log(`\x1b[31mnpm run fleetbo rm\x1b[0m \x1b[36m${moduleName}\x1b[0m`);
609
560
 
610
561
  } else if (aiData.status === 'success' && (!mergedModuleData || Object.keys(mergedModuleData).length === 0)) {
611
- console.log(`\n\x1b[31m⚠️ Error: Alex replied, but source code could not be extracted.\x1b[0m\n`);
562
+ console.log('\x1b[31m[Error] Alex replied, but source code could not be extracted.\x1b[0m\n');
612
563
  }
613
564
  } catch (error) {
614
565
  process.stdout.write('\r' + ' '.repeat(50) + '\r');
615
- console.error('\n\x1b[31m Alex Error:\x1b[0m ' + (error.response?.data?.message || error.message));
566
+ console.error('\x1b[31m[Alex Error]\x1b[0m ' + (error.response?.data?.message || error.message));
616
567
  }
617
568
  };
618
569
 
619
570
  // ============================================================
620
- // DÉMARRAGE DE LA SESSION INTERACTIVE ALEX
571
+ // START INTERACTIVE SESSION
621
572
  // ============================================================
622
573
 
623
574
  const startAlexSession = async () => {
624
- process.stdout.write('\x1b[33m🛡️ Alex is checking runtime state...\x1b[0m\r');
575
+ process.stdout.write('\x1b[33m[Alex] Checking runtime state...\x1b[0m\r');
625
576
  let attempts = 0;
626
577
  const maxAttempts = 5;
627
578
  let isReady = false;
@@ -653,7 +604,7 @@ if (command === 'alex') {
653
604
  }
654
605
 
655
606
  if (!isReady) {
656
- console.error('\n\x1b[31m⚠️ ENGINE OFFLINE:\x1b[0m Start Fleetbo runtime first: "npm run fleetbo" ');
607
+ console.error('\x1b[31m[ENGINE OFFLINE]\x1b[0m Start Fleetbo runtime first: "npm run fleetbo" ');
657
608
  console.error(`\x1b[90m(Ensure you are running the runtime for project: ${keyApp})\x1b[0m`);
658
609
  process.exit(1);
659
610
  }
@@ -661,21 +612,15 @@ if (command === 'alex') {
661
612
  process.stdout.write(' '.repeat(60) + '\r');
662
613
 
663
614
  if (!hasAiKey) {
664
- console.log('');
665
- console.log('\x1b[1m\x1b[33m AI Configuration Required\x1b[0m');
666
- console.log('');
615
+ console.log('\x1b[1m\x1b[33mAI Configuration Required\x1b[0m\n');
667
616
  console.log('Alex needs a powerful AI model to forge native code.');
668
- console.log('Connect your own AI key to continue.');
669
- console.log('');
617
+ console.log('Connect your own AI key to continue.\n');
670
618
  console.log('\x1b[1mSupported providers:\x1b[0m');
671
- console.log('\x1b[32m●\x1b[0m Google AI \x1b[90m(Gemini Pro)\x1b[0m');
672
- console.log('\x1b[36mhttps://aistudio.google.com/app/apikey\x1b[0m');
673
- console.log('');
674
- console.log('\x1b[33m●\x1b[0m Anthropic \x1b[90m(Claude Sonnet / Opus)\x1b[0m');
675
- console.log('\x1b[36mhttps://console.anthropic.com/settings/keys\x1b[0m');
676
- console.log('');
677
- console.log('\x1b[90m Click the \x1b[32m[+]\x1b[90m button in the Terminal top-right bar\x1b[0m');
678
- console.log('');
619
+ console.log('\x1b[32m[+]\x1b[0m Google AI \x1b[90m(Gemini Pro)\x1b[0m');
620
+ console.log('\x1b[36mhttps://aistudio.google.com/app/apikey\x1b[0m\n');
621
+ console.log('\x1b[33m[+]\x1b[0m Anthropic \x1b[90m(Claude Sonnet / Opus)\x1b[0m');
622
+ console.log('\x1b[36mhttps://console.anthropic.com/settings/keys\x1b[0m\n');
623
+ console.log('\x1b[90mClick the \x1b[32m[+]\x1b[90m button in the Terminal top-right bar\x1b[0m\n');
679
624
  process.exit(0);
680
625
  }
681
626
 
@@ -686,32 +631,27 @@ if (command === 'alex') {
686
631
 
687
632
  console.log('\x1b[90m┌─────────────────────────────────────────────────────────┐\x1b[0m');
688
633
  console.log('\x1b[90m│ │\x1b[0m');
689
- console.log('\x1b[90m│\x1b[0m \x1b[1m\x1b[36mALEX\x1b[0m \x1b[90m— System Architect · Fleetbo OS\x1b[0m \x1b[90m│\x1b[0m');
634
+ console.log('\x1b[90m│\x1b[0m \x1b[1m\x1b[36m[ALEX]\x1b[0m \x1b[90m— System Architect · Fleetbo OS\x1b[0m \x1b[90m│\x1b[0m');
690
635
  console.log('\x1b[90m│ │\x1b[0m');
691
636
  console.log('\x1b[90m│\x1b[0m \x1b[90mYour JS stays the brain. I forge the metal.\x1b[0m \x1b[90m│\x1b[0m');
692
637
  console.log('\x1b[90m│ │\x1b[0m');
693
638
  console.log('\x1b[90m└─────────────────────────────────────────────────────────┘\x1b[0m');
694
639
 
695
- console.log('');
696
- console.log(`\x1b[32m✓\x1b[0m ${providerLabel} \x1b[90m· ${modelLabel}\x1b[0m`);
697
- console.log(`\x1b[32m✓\x1b[0m ${JS_FRAMEWORK === 'vue' ? '\x1b[32mVue.js\x1b[0m' : '\x1b[36mReact\x1b[0m'} \x1b[90m· JavaScript Framework\x1b[0m`);
640
+ console.log(`\x1b[32m[OK]\x1b[0m ${providerLabel} \x1b[90m· ${modelLabel}\x1b[0m`);
641
+ console.log(`\x1b[32m[OK]\x1b[0m ${JS_FRAMEWORK === 'vue' ? '\x1b[32mVue.js\x1b[0m' : '\x1b[36mReact\x1b[0m'} \x1b[90m· JavaScript Framework\x1b[0m\n`);
698
642
 
699
- console.log('');
700
643
  console.log('\x1b[36mCAPABILITIES\x1b[0m');
701
644
  console.log('\x1b[90m─────────────────────────────────────────────────────\x1b[0m');
702
645
  console.log('\x1b[1mHardware\x1b[0m\x1b[90m Camera · Scanner · GPS · Biometrics\x1b[0m');
703
646
  console.log('\x1b[1mHigh-Perf\x1b[0m\x1b[90m Video Feed · Swipe Deck · Audio\x1b[0m');
704
647
  console.log('\x1b[1mSovereign\x1b[0m\x1b[90m Form + Photo + Save-to-Cloud\x1b[0m');
705
648
  console.log('\x1b[1mFleetbo View\x1b[0m\x1b[90m Full native tab (120 FPS)\x1b[0m');
706
- console.log('\x1b[90m─────────────────────────────────────────────────────\x1b[0m');
649
+ console.log('\x1b[90m─────────────────────────────────────────────────────\x1b[0m\n');
707
650
 
708
- console.log('');
709
651
  console.log('\x1b[36mCODE GENERATION SYNTAX\x1b[0m \x1b[90m(strict format required)\x1b[0m');
710
- console.log('');
711
652
  console.log('\x1b[90mFormat: \x1b[33m<verb>\x1b[0m module \x1b[36m<ModuleName>\x1b[0m');
712
653
  console.log('\x1b[90mVerbs: \x1b[33mforge\x1b[0m \x1b[90m·\x1b[0m \x1b[33mcreate\x1b[0m \x1b[90m·\x1b[0m \x1b[33mupdate\x1b[0m \x1b[90m·\x1b[0m \x1b[33mmodify\x1b[0m \x1b[90m·\x1b[0m \x1b[33mfix\x1b[0m \x1b[90m·\x1b[0m \x1b[33medit\x1b[0m');
713
- console.log('\x1b[90mExample: \x1b[0m\x1b[33mupdate\x1b[0m module \x1b[36mProfileManager\x1b[0m \x1b[90mwith a red button\x1b[0m');
714
- console.log('');
654
+ console.log('\x1b[90mExample: \x1b[0m\x1b[33mupdate\x1b[0m module \x1b[36mProfileManager\x1b[0m \x1b[90mwith a red button\x1b[0m\n');
715
655
 
716
656
  console.log('\x1b[32mAlex ❯\x1b[0m Describe your feature using the Compose panel...');
717
657
 
@@ -721,7 +661,7 @@ if (command === 'alex') {
721
661
  });
722
662
 
723
663
  rl.on('SIGINT', () => {
724
- console.log('\n\x1b[90m Alex session aborted (Ctrl+C).\x1b[0m');
664
+ console.log('\x1b[90mAlex session aborted (Ctrl+C).\x1b[0m');
725
665
  process.stdout.write('[ALEX_OFFLINE]\n');
726
666
  rl.close();
727
667
  process.exit(0);
@@ -732,7 +672,7 @@ if (command === 'alex') {
732
672
 
733
673
  const executePrompt = async (text) => {
734
674
  if (['exit', 'quit'].includes(text.toLowerCase())) {
735
- console.log('\n\x1b[90m Alex session closed.\x1b[0m');
675
+ console.log('\x1b[90mAlex session closed.\x1b[0m');
736
676
  process.stdout.write('[ALEX_OFFLINE]\n');
737
677
  rl.close();
738
678
  return;
@@ -740,9 +680,7 @@ if (command === 'alex') {
740
680
 
741
681
  if (text !== "") {
742
682
  isProcessing = true;
743
-
744
683
  await processAlexRequest(text);
745
-
746
684
  isProcessing = false;
747
685
  console.log('');
748
686
  }
@@ -781,16 +719,14 @@ if (command === 'alex') {
781
719
  else if (command === 'rm') {
782
720
  const moduleName = args[1];
783
721
  if (!moduleName) {
784
- console.error('\n\x1b[31mError: Module name required.\x1b[0m');
722
+ console.error('\x1b[31m[Error] Module name required.\x1b[0m');
785
723
  console.log('\x1b[90mUsage: npm run fleetbo rm [ModuleName]\x1b[0m\n');
786
724
  process.exit(1);
787
725
  }
788
726
 
789
- console.log(`\n\x1b[33m🗑️ Annihilating module: ${moduleName}...\x1b[0m`);
727
+ console.log(`\x1b[33m[Annihilation] Removing module: ${moduleName}...\x1b[0m`);
790
728
 
791
- // 1. Define physical paths
792
729
  const ktPath = path.join(process.cwd(), 'public', 'native', 'android', `${moduleName}.kt`);
793
- // AGNOSTIQUE — cherche .jsx (React) puis .vue (Vue)
794
730
  const jsxPath = path.join(process.cwd(), 'src', 'app', 'mocks', `${moduleName}.jsx`);
795
731
  const vuePath = path.join(process.cwd(), 'src', 'app', 'mocks', `${moduleName}.vue`);
796
732
  const mockPath = fs.existsSync(jsxPath) ? jsxPath : fs.existsSync(vuePath) ? vuePath : null;
@@ -798,28 +734,25 @@ else if (command === 'rm') {
798
734
 
799
735
  let actionsDone = 0;
800
736
 
801
- // 2. Eradicate Metal Engine (Kotlin)
802
737
  if (fs.existsSync(ktPath)) {
803
738
  fs.unlinkSync(ktPath);
804
- console.log(` \x1b[32m[Deleted]\x1b[0m Metal file (.kt) eradicated.`);
739
+ console.log(`\x1b[32m[Deleted]\x1b[0m Metal file (.kt) eradicated.`);
805
740
  actionsDone++;
806
741
  }
807
742
 
808
- // 3. Eradicate Virtual Twin (Mock JSX or Vue)
809
743
  if (mockPath) {
810
744
  fs.unlinkSync(mockPath);
811
- console.log(` \x1b[32m[Deleted]\x1b[0m Virtual Twin (${mockExt}) eradicated.`);
745
+ console.log(`\x1b[32m[Deleted]\x1b[0m Virtual Twin (${mockExt}) eradicated.`);
812
746
  actionsDone++;
813
747
  }
814
748
 
815
- // 4. Disinfect System Core (App.jsx)
816
749
  const unrouted = removeRouteFromAppJs(moduleName);
817
750
  if (unrouted) actionsDone++;
818
751
 
819
752
  if (actionsDone === 0) {
820
- console.log(`\n\x1b[31m⚠️ No trace of module "${moduleName}" found in the OS.\x1b[0m\n`);
753
+ console.log(`\x1b[31m[Warning] No trace of module "${moduleName}" found in the OS.\x1b[0m\n`);
821
754
  } else {
822
- console.log(`\n\x1b[32m Module ${moduleName} successfully eradicated from the OS.\x1b[0m\n`);
755
+ console.log(`\x1b[32mModule ${moduleName} successfully eradicated from the OS.\x1b[0m\n`);
823
756
  }
824
757
  }
825
758
 
@@ -828,21 +761,17 @@ else if (command === 'rm') {
828
761
  // ============================================
829
762
  else if (command === 'android' || command === 'ios') {
830
763
 
831
- // DÉBUT DE LA PROTECTION (Fonction Async Immédiate)
832
- // Cela garantit que le code fonctionne partout, même via 'require()'
833
764
  (async () => {
834
765
 
835
- // 🛑 INTERCEPTION IOS : BLOQUAGE NET (MAINTENANCE/BETA)
836
766
  if (command === 'ios') {
837
- console.log(`\n\x1b[36mFLEETBO IOS PROPULSION\x1b[0m`);
767
+ console.log(`\x1b[36m[FLEETBO IOS PROPULSION]\x1b[0m`);
838
768
  console.log(`\x1b[33m[0/3] Initializing Neural Uplink...\x1b[0m`);
839
769
 
840
- // Ce 'await' est maintenant sécurisé
841
770
  await new Promise(r => setTimeout(r, 800));
842
771
 
843
- console.log(`\n\x1b[31mPROPULSION ABORTED: iOS Frequency Restricted.\x1b[0m`);
844
- console.log(`\x1b[90m This module is currently reserved for Vanguard Pilots (Closed Beta).\x1b[0m`);
845
- console.log(`\x1b[90m Please engage propulsion on Android frequency for now.\x1b[0m\n`);
772
+ console.log(`\x1b[31m[PROPULSION ABORTED] iOS Frequency Restricted.\x1b[0m`);
773
+ console.log(`\x1b[90mThis module is currently reserved for Vanguard Pilots (Closed Beta).\x1b[0m`);
774
+ console.log(`\x1b[90mPlease engage propulsion on Android frequency for now.\x1b[0m\n`);
846
775
 
847
776
  process.exit(1);
848
777
  }
@@ -853,7 +782,6 @@ else if (command === 'android' || command === 'ios') {
853
782
  const extension = platform === 'android' ? '.kt' : '.swift';
854
783
  const nativePath = path.join(process.cwd(), nativeDir);
855
784
 
856
- // Vérification des modules natifs
857
785
  let hasNativeFiles = false;
858
786
  let nativeFileCount = 0;
859
787
  if (fs.existsSync(nativePath)) {
@@ -864,7 +792,7 @@ else if (command === 'android' || command === 'ios') {
864
792
  }
865
793
 
866
794
  if (!hasNativeFiles) {
867
- console.log(`\n\x1b[31m⚠️ ENGINE INCOMPLETE:\x1b[0m No native blueprints detected for \x1b[1m${platform.toUpperCase()}\x1b[0m.`);
795
+ console.log(`\x1b[31m[ENGINE INCOMPLETE]\x1b[0m No native blueprints detected for \x1b[1m${platform.toUpperCase()}\x1b[0m.`);
868
796
  console.log(`\x1b[90mAlex must architect at least one ${extension} module before deployment.\x1b[0m`);
869
797
  console.log(`\x1b[90mRun: npm run fleetbo alex\x1b[0m\n`);
870
798
  process.exit(1);
@@ -872,23 +800,18 @@ else if (command === 'android' || command === 'ios') {
872
800
 
873
801
  const targetUrl = platform === 'android' ? ANDROID_BUILD_URL : IOS_BUILD_URL;
874
802
 
875
- console.log(`\n\x1b[36mFLEETBO ${platform.toUpperCase()} PROPULSION\x1b[0m`);
876
- console.log(`\x1b[90m ${nativeFileCount} fleetbo module(s) detected\x1b[0m\n`);
803
+ console.log(`\x1b[36m[FLEETBO ${platform.toUpperCase()} PROPULSION]\x1b[0m`);
804
+ console.log(`\x1b[90m${nativeFileCount} fleetbo module(s) detected\x1b[0m\n`);
877
805
 
878
806
  try {
879
- // ==========================================================
880
- // PRE-FLIGHT CHECK QUOTAS & TIER
881
- // ==========================================================
882
807
  process.stdout.write(`\x1b[33m[0/3]\x1b[0m Checking Propulsion Access... `);
883
808
  try {
884
- // On envoie le signal 'x-preflight' pour tester les droits sans builder
885
809
  await axios.post(targetUrl, {}, {
886
810
  headers: {
887
811
  'x-project-id': projectId,
888
812
  'x-preflight': 'true'
889
813
  }
890
814
  });
891
- // Si ça passe (200 OK), c'est un Senior ou un Junior autorisé (si vous changez d'avis)
892
815
  process.stdout.write(`\x1b[32mOK (Senior Pilot)\x1b[0m\n\n`);
893
816
 
894
817
  } catch (preflightError) {
@@ -896,27 +819,21 @@ else if (command === 'android' || command === 'ios') {
896
819
 
897
820
  const errData = preflightError.response?.data;
898
821
 
899
- // 🛑 1. INTERCEPTION SPÉCIFIQUE JUNIOR
900
- // C'est ici qu'on lit le code renvoyé par index.js
901
822
  if (errData?.code === 'junior_restriction') {
902
- console.log(`\n\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
903
- console.log(`\x1b[31m⛔ ACCESS DENIED: JUNIOR PILOT DETECTED\x1b[0m`);
904
823
  console.log(`\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
905
- console.log(``);
906
- console.log(` \x1b[33m This feature is locked for Junior Pilots.\x1b[0m`);
907
- console.log(` \x1b[32m Upgrade to Senior on fleetbo.io to unlock Propulsion.\x1b[0m`);
908
- console.log(``);
909
- process.exit(1); // Arrêt immédiat et propre du script
824
+ console.log(`\x1b[31m[ACCESS DENIED] JUNIOR PILOT DETECTED\x1b[0m`);
825
+ console.log(`\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\n`);
826
+ console.log(`\x1b[33mThis feature is locked for Junior Pilots.\x1b[0m`);
827
+ console.log(`\x1b[32mUpgrade to Senior on fleetbo.io to unlock Propulsion.\x1b[0m\n`);
828
+ process.exit(1);
910
829
  }
911
830
 
912
- // 2. Gestion des autres erreurs (Quota Senior dépassé, Serveur HS, etc.)
913
831
  if (errData && errData.error) {
914
832
  throw new Error(errData.error);
915
833
  }
916
834
  throw preflightError;
917
835
  }
918
836
 
919
- // Étape 1: Build React
920
837
  console.log(`\x1b[33m[1/3]\x1b[0m Synthesizing Fleetbo Core Logic...`);
921
838
  execSync('npm run build', { stdio: 'inherit' });
922
839
 
@@ -927,8 +844,7 @@ else if (command === 'android' || command === 'ios') {
927
844
  throw new Error(`Build directory not found: ${buildDir}`);
928
845
  }
929
846
 
930
- // Étape 2: Créer le ZIP
931
- console.log(`\n\x1b[33m[2/3]\x1b[0m Packaging bundle + fleetbo modules...`);
847
+ console.log(`\x1b[33m[2/3]\x1b[0m Packaging bundle + fleetbo modules...`);
932
848
 
933
849
  const zipBuffer = await new Promise((resolve, reject) => {
934
850
  const chunks = [];
@@ -949,10 +865,9 @@ else if (command === 'android' || command === 'ios') {
949
865
  });
950
866
 
951
867
  const sizeMB = (zipBuffer.length / 1024 / 1024).toFixed(2);
952
- console.log(` \x1b[32m✓\x1b[0m Bundle ready: ${sizeMB} MB`);
868
+ console.log(`\x1b[32m[Ready]\x1b[0m Bundle ready: ${sizeMB} MB`);
953
869
 
954
- // Étape 3: Upload
955
- console.log(`\n\x1b[33m[3/3]\x1b[0m Uploading to Fleetbo OS...`);
870
+ console.log(`\x1b[33m[3/3]\x1b[0m Uploading to Fleetbo OS...`);
956
871
  await showEnergyTransfer();
957
872
 
958
873
  let uploadResponse;
@@ -975,28 +890,28 @@ else if (command === 'android' || command === 'ios') {
975
890
  }
976
891
 
977
892
  if (uploadResponse.data && uploadResponse.data.success) {
978
- console.log(`\n\x1b[32m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
979
- console.log(`\x1b[32m✓ ${platform.toUpperCase()} PROPULSION SUCCESSFUL\x1b[0m`);
980
893
  console.log(`\x1b[32m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
981
- console.log(`\x1b[90m Deployment ID: ${uploadResponse.data.deploymentId || 'N/A'}\x1b[0m`);
982
- console.log(`\x1b[90m ${uploadResponse.data.message || 'Complete.'}\x1b[0m\n`);
894
+ console.log(`\x1b[32m[SUCCESS] ${platform.toUpperCase()} PROPULSION SUCCESSFUL\x1b[0m`);
895
+ console.log(`\x1b[32m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
896
+ console.log(`\x1b[90mDeployment ID: ${uploadResponse.data.deploymentId || 'N/A'}\x1b[0m`);
897
+ console.log(`\x1b[90m${uploadResponse.data.message || 'Complete.'}\x1b[0m\n`);
983
898
  } else {
984
899
  throw new Error(uploadResponse.data?.error || 'Unknown logical error from Factory');
985
900
  }
986
901
 
987
902
  } catch (error) {
988
- console.log(`\n\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
989
- console.log(`\x1b[31m PROPULSION FAILED\x1b[0m`);
903
+ console.log(`\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
904
+ console.log(`\x1b[31m[Propulsion Failed]\x1b[0m`);
990
905
  console.log(`\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
991
906
 
992
- console.error(`\x1b[31m Error:\x1b[0m ${error.message}`);
907
+ console.error(`\x1b[31m[Error]\x1b[0m ${error.message}`);
993
908
 
994
909
  if (error.message.includes('Limit') || error.message.includes('Quota')) {
995
- console.log(`\n\x1b[33m Tip:\x1b[0m Upgrade to Senior Pilot for more builds.`);
910
+ console.log(`\x1b[33m[Tip]\x1b[0m Upgrade to Senior Pilot for more builds.`);
996
911
  } else if (error.message.includes('No native module')) {
997
- console.log(`\n\x1b[33m Tip:\x1b[0m Run "npm run fleetbo alex" to create native modules first.`);
912
+ console.log(`\x1b[33m[Tip]\x1b[0m Run "npm run fleetbo alex" to create native modules first.`);
998
913
  } else if (error.message.includes('Trial Period Ended')) {
999
- console.log(`\n\x1b[33m Tip:\x1b[0m Your free sprint is over. Upgrade to Senior Pilot on fleetbo.io.`);
914
+ console.log(`\x1b[33m[Tip]\x1b[0m Your free sprint is over. Upgrade to Senior Pilot on fleetbo.io.`);
1000
915
  }
1001
916
  console.log('');
1002
917
  process.exit(1);
@@ -1012,7 +927,7 @@ else if (['page', 'g', 'generate'].includes(command)) {
1012
927
  try {
1013
928
  require(pageGeneratorPath);
1014
929
  } catch (e) {
1015
- console.error('\x1b[31m Page Generator Error:\x1b[0m', e.message);
930
+ console.error('\x1b[31m[Page Generator Error]\x1b[0m', e.message);
1016
931
  process.exit(1);
1017
932
  }
1018
933
  }
@@ -1053,10 +968,10 @@ else {
1053
968
  async function cleanupAndExit(code = 0) {
1054
969
  if (isExiting) return;
1055
970
  isExiting = true;
1056
- console.log('\n\x1b[33m[Fleetbo] 🛑 Stopping environment & Cleaning Uplink...\x1b[0m');
971
+ console.log('\x1b[33m[Fleetbo] Stopping environment & Cleaning Uplink...\x1b[0m');
1057
972
  try {
1058
973
  await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl: '', tester: testerEmail });
1059
- console.log('\x1b[32m[Fleetbo] Network status reset to offline.\x1b[0m');
974
+ console.log('\x1b[32m[Fleetbo] Network status reset to offline.\x1b[0m');
1060
975
  } catch (e) {
1061
976
  console.error('[Fleetbo] Network cleanup warning:', e.message);
1062
977
  }
@@ -1066,7 +981,6 @@ else {
1066
981
  process.exit(code);
1067
982
  }
1068
983
 
1069
- // 🪟 WINDOWS FIX : capture Ctrl+C via readline pour éviter l'invite "O/N"
1070
984
  if (process.platform === 'win32') {
1071
985
  const rlWin = require('readline').createInterface({ input: process.stdin, output: process.stdout });
1072
986
  rlWin.on('SIGINT', () => cleanupAndExit(0));
@@ -1078,31 +992,30 @@ else {
1078
992
  async function syncFirebase(keyApp, networkUrl, testerEmail) {
1079
993
  try {
1080
994
  await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl, tester: testerEmail });
1081
- console.log('\n\x1b[32mEngine started successfully\x1b[0m');
1082
- console.log(`\n\x1b[32mFleetbo OS ❯\x1b[0m -------------------------------------------------------------`);
995
+ console.log('\x1b[32mEngine started successfully\x1b[0m');
996
+ console.log(`\x1b[32mFleetbo OS ❯\x1b[0m -------------------------------------------------------------`);
1083
997
  console.log(`\x1b[32mFleetbo OS ❯\x1b[0m \x1b[1mProject [${keyApp}] running in OS\x1b[0m`);
1084
998
  console.log('\x1b[32mFleetbo OS ❯\x1b[0m You can now start coding and previewing.');
1085
999
  console.log(`\x1b[32mFleetbo OS ❯\x1b[0m -------------------------------------------------------------`);
1086
- console.log(`\n\x1b[34mPilot Instruction ❯\x1b[0m Return to the Workspace. The Engine is ready for your orders.\n`);
1000
+ console.log(`\x1b[34mPilot Instruction ❯\x1b[0m Return to the Workspace. The Engine is ready for your orders.\n`);
1087
1001
  } catch (err) {
1088
1002
  console.error(`\x1b[31mFleetbo OS ❯\x1b[0m Sync Error: ${err.message}`);
1089
1003
  }
1090
1004
  }
1091
1005
 
1092
1006
  async function runDevEnvironment() {
1093
- console.log(`[Fleetbo] Initializing Universal Dev Environment...`);
1007
+ console.log(`[Fleetbo] Initializing Universal Dev Environment...`);
1094
1008
 
1095
1009
  killNetworkService();
1096
- killProcessOnPort(PORT); // On tue le 3000 par précaution, au cas où
1010
+ killProcessOnPort(PORT);
1097
1011
 
1098
1012
  if (!testerEmail) {
1099
- console.error('\x1b[31mError: FLEETBO_APP_TESTER_EMAIL missing in .env\x1b[0m');
1013
+ console.error('\x1b[31m[Error] FLEETBO_APP_TESTER_EMAIL missing in .env\x1b[0m');
1100
1014
  process.exit(1);
1101
1015
  }
1102
1016
 
1103
1017
  const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
1104
1018
 
1105
- // Lancement agnostique du serveur de dev (React, Vue, etc.)
1106
1019
  const devServer = spawn(`${npmCmd} run dev --silent -- --host 127.0.0.1 --port ${PORT}`, {
1107
1020
  stdio: ['ignore', 'pipe', 'pipe'],
1108
1021
  shell: true,
@@ -1115,12 +1028,11 @@ else {
1115
1028
  devServer.stderr.pipe(process.stderr);
1116
1029
 
1117
1030
  let connectionStarted = false;
1118
- let detectedPort = PORT; // 3000 par défaut
1031
+ let detectedPort = PORT;
1119
1032
 
1120
1033
  devServer.stdout.on('data', (data) => {
1121
1034
  const output = data.toString();
1122
1035
 
1123
- // FILTRE ANTI-PLOMBERIE FLEETBO
1124
1036
  const lines = output.split('\n');
1125
1037
  const forbiddenTerms = [
1126
1038
  'Attempting to bind to HOST', 'If this was unintentional', 'Learn more here:',
@@ -1137,22 +1049,17 @@ else {
1137
1049
  process.stdout.write(filteredOutput + '\n');
1138
1050
  }
1139
1051
 
1140
- // MAGIE 1 : DÉTECTION DU PORT RÉEL (Vite/Vue ou React)
1141
- // Cherche un pattern comme http://localhost:5173 ou http://127.0.0.1:3000
1142
- // LA SOLUTION : On déclenche UNIQUEMENT quand on a trouvé le port !
1143
- // CAPTURE AGNOSTIQUE DU PORT (S'adapte dynamiquement à Vite)
1144
1052
  const portMatch = output.match(/http:\/\/(?:localhost|127\.0\.0\.1):(\d+)/);
1145
1053
 
1146
1054
  if (portMatch) {
1147
- detectedPort = portMatch[1]; // Capture le port final choisi par Vite
1055
+ detectedPort = portMatch[1];
1148
1056
 
1149
- // On lance le tunnel Cloudflare UNIQUEMENT sur ce port définitif
1150
1057
  if (!connectionStarted) {
1151
1058
  connectionStarted = true;
1152
1059
 
1153
- console.log('\n\x1b[33mFleetbo OS ❯\x1b[0m ---------------------------------------------------');
1154
- console.log(`\x1b[33mFleetbo OS ❯\x1b[0m Establishing Secure Uplink...`);
1155
- console.log(`\x1b[33mFleetbo OS ❯\x1b[0m Please wait for the green message...`);
1060
+ console.log('\x1b[33mFleetbo OS ❯\x1b[0m ---------------------------------------------------');
1061
+ console.log(`\x1b[33mFleetbo OS ❯\x1b[0m Establishing Secure Uplink...`);
1062
+ console.log(`\x1b[33mFleetbo OS ❯\x1b[0m Please wait for the green message...`);
1156
1063
  console.log('\x1b[33mFleetbo OS ❯\x1b[0m ---------------------------------------------------');
1157
1064
 
1158
1065
  const MAX_UPLINK_RETRIES = 5;
@@ -1165,10 +1072,9 @@ else {
1165
1072
  const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
1166
1073
 
1167
1074
  if (attempt > 0) {
1168
- console.log(`\x1b[33m[Fleetbo] Uplink reconnection ${attempt}/${MAX_UPLINK_RETRIES - 1}...\x1b[0m`);
1075
+ console.log(`\x1b[33m[Fleetbo] Uplink reconnection ${attempt}/${MAX_UPLINK_RETRIES - 1}...\x1b[0m`);
1169
1076
  }
1170
1077
 
1171
- // LE TUNNEL CLOUDFLARE UTILISE LE PORT DÉTECTÉ DYNAMIQUEMENT !
1172
1078
  const uplinkCommand = `${npxCmd} -y cloudflared tunnel --url http://127.0.0.1:${detectedPort} --http-host-header 127.0.0.1:${detectedPort}`;
1173
1079
  uplinkProcess = spawn(uplinkCommand, { shell: true });
1174
1080
 
@@ -1189,7 +1095,7 @@ else {
1189
1095
 
1190
1096
  uplinkProcess.on('error', () => {
1191
1097
  if (uplinkFound) return;
1192
- console.error(`\x1b[31m[Fleetbo] ⚠️ Uplink Connection failed to establish.\x1b[0m`);
1098
+ console.error(`\x1b[31m[Fleetbo] Uplink Connection failed to establish.\x1b[0m`);
1193
1099
  });
1194
1100
 
1195
1101
  uplinkProcess.on('close', () => {
@@ -1197,10 +1103,10 @@ else {
1197
1103
  const nextAttempt = attempt + 1;
1198
1104
  if (nextAttempt < MAX_UPLINK_RETRIES) {
1199
1105
  const delay = RETRY_DELAYS[nextAttempt] || 30;
1200
- console.log(`\x1b[33m[Fleetbo] ⚠️ Uplink interrupted. Fleetbo OS retrying in ${delay}s... (${nextAttempt}/${MAX_UPLINK_RETRIES - 1})\x1b[0m`);
1106
+ console.log(`\x1b[33m[Fleetbo] Uplink interrupted. Fleetbo OS retrying in ${delay}s... (${nextAttempt}/${MAX_UPLINK_RETRIES - 1})\x1b[0m`);
1201
1107
  setTimeout(() => startUplink(nextAttempt), delay * 1000);
1202
1108
  } else {
1203
- console.error(`\x1b[31m[Fleetbo] Secure Uplink could not be established.\x1b[0m`);
1109
+ console.error(`\x1b[31m[Fleetbo] Secure Uplink could not be established.\x1b[0m`);
1204
1110
  }
1205
1111
  });
1206
1112
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbo-cockpit-cli",
3
- "version": "1.0.217",
3
+ "version": "1.0.219",
4
4
  "description": "Fleetbo CLI - Build native mobile apps with React",
5
5
  "author": "Fleetbo",
6
6
  "license": "MIT",