fleetbo-cockpit-cli 1.0.218 → 1.0.220

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 +151 -236
  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,36 @@ 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
- 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`);
317
+ console.log(`[${m.platform}] \x1b[1m${m.moduleName}\x1b[0m`);
350
318
  });
351
319
  } else {
352
- console.log(`\n \x1b[90mNo modules found in the infrastructure of this project.\x1b[0m`);
320
+ console.log(`\x1b[90mNo modules found in the infrastructure of this project.\x1b[0m`);
353
321
  }
354
322
  return;
355
323
  }
356
324
 
357
- console.log('\x1b[33m🧠 Alex is thinking...\x1b[0m');
325
+ console.log('\x1b[33m[Alex] Processing request...\x1b[0m');
358
326
 
359
327
  try {
360
- // --- MEMORY SYSTEM (SMART CACHE SCANNER V3 - SOUVERAINETÉ DU MÉTAL) ---
328
+ // --- MEMORY SYSTEM (SMART CACHE SCANNER V3) ---
361
329
  let contextInjection = "";
362
330
  const potentialModules = extractPotentialModules(prompt);
363
331
 
@@ -367,7 +335,6 @@ if (command === 'alex') {
367
335
  for (let modName of potentialModules) {
368
336
  let isReferenceOnly = false;
369
337
 
370
- // LE DÉTECTEUR D'INSPIRATION
371
338
  if (modName.endsWith('Ref')) {
372
339
  isReferenceOnly = true;
373
340
  modName = modName.replace('Ref', '');
@@ -376,67 +343,59 @@ if (command === 'alex') {
376
343
  modName = modName.replace('Schema', '');
377
344
  }
378
345
 
379
- process.stdout.write(` \x1b[90m Checking Alex memory for ${modName} module...\x1b[0m`);
346
+ process.stdout.write(`\x1b[90mChecking Alex memory for ${modName} module...\x1b[0m `);
380
347
  const cache = await getModuleCache({ projectId, moduleName: modName });
381
348
 
382
- // LECTURE LOCALE DU VRAI CODE KOTLIN (La Vérité Absolue)
383
349
  const localKtPath = path.join(process.cwd(), 'public', 'native', 'android', `${modName}.kt`);
384
350
  let actualMetalCode = "";
385
351
 
386
352
  if (fs.existsSync(localKtPath)) {
387
353
  actualMetalCode = fs.readFileSync(localKtPath, 'utf8');
388
354
  } else if (cache.found && cache.module.code) {
389
- actualMetalCode = cache.module.code; // Fallback sur le cache si le fichier local n'est pas trouvé
355
+ actualMetalCode = cache.module.code;
390
356
  }
391
357
 
392
358
  if (actualMetalCode) {
393
- process.stdout.write(` \x1b[32mFOUND METAL\x1b[0m\n`);
359
+ process.stdout.write(`\x1b[32m[FOUND METAL]\x1b[0m\n`);
394
360
 
395
- // Extraction des schémas mémoires (uniquement dispo dans le cache cloud)
396
361
  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`;
362
+ if (cache.found && cache.module.dataSchema) memoryScript += `\n[DATA MEMORY SCRIPT]\n${cache.module.dataSchema}\n`;
363
+ if (cache.found && cache.module.uiSchema) memoryScript += `\n[NATIVE UI MEMORY SCRIPT]\n${cache.module.uiSchema}\n`;
399
364
 
400
- if (!memoryScript) memoryScript = `\n[SCRIPT MÉMOIRE DU MODULE ${modName}]\nAucun schéma enregistré pour ce module.\n`;
365
+ if (!memoryScript) memoryScript = `\n[MODULE MEMORY SCRIPT ${modName}]\nNo schema registered for this module.\n`;
401
366
 
402
- // 🤖 PRÉ-ANALYSE DÉTERMINISTE DU CLI (Le bouclier anti-amnésie d'Alex)
403
367
  const isTabModule = actualMetalCode.includes('action == "tab"');
404
368
  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"
369
+ ? "\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
370
  : "";
407
371
 
408
372
  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`;
373
+ 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
374
  } else if (!targetModuleContext) {
412
- // 🚨 CAS B : CIBLE PRINCIPALE
413
375
  const intent = getContextIntent(prompt);
414
376
  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`;
377
+ 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
378
  } 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`;
379
+ 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
380
  }
419
381
  }
420
382
  } else {
421
- process.stdout.write(` \x1b[31mNOT FOUND\x1b[0m\n`);
383
+ process.stdout.write(`\x1b[31m[NOT FOUND]\x1b[0m\n`);
422
384
  }
423
385
  }
424
386
 
425
387
  contextInjection = referenceContexts + targetModuleContext;
426
388
  if (contextInjection) {
427
- prompt = contextInjection + "\n\n[INSTRUCTION DU PILOTE]\n" + prompt;
389
+ prompt = contextInjection + "\n\n[PILOT INSTRUCTION]\n" + prompt;
428
390
  }
429
- // --- END MEMORY MODIFICATION ---
430
391
 
431
- // Real-time timestamp injection
432
392
  const now = new Date();
433
- // Clean format: YYYY-MM-DD at HH:MM:SS
434
393
  const exactTime = now.toISOString().split('T')[0] + ' at ' + now.toTimeString().split(' ')[0];
435
394
 
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.]`;
395
+ 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
396
 
438
397
  // =================================================================
439
- // 🚀 THE AUTOMATED 3-STEP WORKFLOW (Cross-Platform)
398
+ // THE AUTOMATED 3-STEP WORKFLOW (Cross-Platform)
440
399
  // =================================================================
441
400
 
442
401
  const deepUnwrap = (raw, depth = 0) => {
@@ -476,46 +435,46 @@ if (command === 'alex') {
476
435
  return deepUnwrap(res.data);
477
436
  };
478
437
 
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}`);
438
+ const logStep = (prefix, text) => {
439
+ process.stdout.write(`\x1b[2K\r${prefix} ${text}`);
483
440
  };
484
441
 
485
442
  process.stdout.write('\x1b[A\r' + ' '.repeat(50) + '\r');
486
443
 
487
- // --- ÉTAPE 1 : NATIF ---
488
- logStep('🧠', '\x1b[33m1/3 - Alex forge les fondations natives...\x1b[0m');
444
+ let totalTokens = 0;
445
+
446
+ // --- STEP 1: NATIVE ---
447
+ logStep('[1/3]', '\x1b[33mAlex is forging native foundations...\x1b[0m');
489
448
  let aiData = await fetchStep('native_only');
490
449
 
491
450
  if (aiData.status === 'quota_exceeded') {
492
- console.log(`\n\x1b[31m ARCHITECT QUOTA REACHED:\x1b[0m ${aiData.message}`);
451
+ console.log(`\n\x1b[31m[Architect Quota Reached]:\x1b[0m ${aiData.message}`);
493
452
  return;
494
453
  }
495
454
 
455
+ totalTokens += aiData.tokensUsed || 0;
456
+
496
457
  let mergedModuleData = aiData.moduleData || {};
497
458
  let aiDataMessage = aiData.message;
498
459
 
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
460
  const isCloudUpdated = !mergedModuleData.mockCode;
503
461
 
504
462
  if (isCloudUpdated && mergedModuleData.code) {
505
- logStep('', '\x1b[32m1/3 - Code Natif généré.\x1b[0m\n');
463
+ logStep('[1/3]', '\x1b[32mNative code generated.\x1b[0m\n');
506
464
 
507
- // --- ÉTAPE 2 : MOCK ---
508
- logStep('🎨', '\x1b[33m2/3 - Analyse du Natif et génération de l\'Interface (Mock)...\x1b[0m');
465
+ // --- STEP 2: MOCK ---
466
+ logStep('[2/3]', '\x1b[33mAnalyzing native code and generating Interface (Mock)...\x1b[0m');
509
467
  const aiData2 = await fetchStep('mock_only', { nativeCode: mergedModuleData.code });
510
468
 
511
469
  if (aiData2.moduleData) {
512
470
  mergedModuleData.mockCode = aiData2.moduleData.mockCode;
513
471
  mergedModuleData.mockFileName = aiData2.moduleData.mockFileName;
514
472
  }
515
- logStep('✅', '\x1b[32m2/3 - Interface Mock générée.\x1b[0m\n');
473
+ totalTokens += aiData2.tokensUsed || 0;
474
+ logStep('[2/3]', '\x1b[32mInterface Mock generated.\x1b[0m\n');
516
475
 
517
- // --- ÉTAPE 3 : JSON CONFIG ---
518
- logStep('⚙️', '\x1b[33m3/3 - Finalisation de la plomberie JSON...\x1b[0m');
476
+ // --- STEP 3: JSON CONFIG ---
477
+ logStep('[3/3]', '\x1b[33mFinalizing JSON configuration...\x1b[0m');
519
478
  const aiData3 = await fetchStep('json_only', {
520
479
  nativeCode: mergedModuleData.code,
521
480
  mockCode: mergedModuleData.mockCode
@@ -526,18 +485,16 @@ if (command === 'alex') {
526
485
  mergedModuleData.dataSchema = aiData3.moduleData.dataSchema;
527
486
  mergedModuleData.uiSchema = aiData3.moduleData.uiSchema;
528
487
  }
529
- logStep('✅', '\x1b[32m3/3 - Configuration terminée.\x1b[0m\n');
488
+ totalTokens += aiData3.tokensUsed || 0;
489
+ logStep('[3/3]', '\x1b[32mConfiguration completed.\x1b[0m\n');
530
490
  } else {
531
- // Le cloud n'est pas à jour, on efface le loader de l'étape 1 en silence
532
491
  process.stdout.write(`\x1b[2K\r`);
533
492
  }
534
493
 
535
- // DISPLAY REASONING IN TERMINAL
536
494
  if (aiData.thinking_process) {
537
- console.log(` \x1b[90m🧠 Alex Analysis: ${aiData.thinking_process.substring(0, 150)}...\x1b[0m`);
495
+ console.log(`\x1b[90m[Analysis] ${aiData.thinking_process.substring(0, 150)}...\x1b[0m`);
538
496
  }
539
497
 
540
- // --- OUTPUT VERS XTERM ---
541
498
  if (aiData.status === 'success' || aiData.status === 'message' || aiData.status === 'complex_refusal') {
542
499
  let rawMsg = aiDataMessage || "I'm ready.";
543
500
  if (typeof rawMsg === 'object') {
@@ -555,7 +512,7 @@ if (command === 'alex') {
555
512
  if (moduleName.length > 40) moduleName = moduleName.substring(0, 40) + "...";
556
513
  }
557
514
 
558
- console.log(`\n \x1b[90mArchitecting: ${moduleName || 'Unknown Module'}\x1b[0m`);
515
+ console.log(`\x1b[90mArchitecting: ${moduleName || 'Unknown Module'}\x1b[0m`);
559
516
 
560
517
  const writeFile = (dir, name, content) => {
561
518
  const fullPath = path.join(process.cwd(), dir);
@@ -578,7 +535,7 @@ if (command === 'alex') {
578
535
 
579
536
  // --- KERNEL SYNCHRONIZATION ---
580
537
  const depsCount = config_offload?.dependencies?.length || 0;
581
- process.stdout.write(` \x1b[33m[OS Sync]\x1b[0m Archiving ${moduleName} to OS (${depsCount} libs)...`);
538
+ process.stdout.write(`\x1b[33m[OS Sync]\x1b[0m Archiving ${moduleName} to OS (${depsCount} libs)... `);
582
539
 
583
540
  try {
584
541
  await axios.post(INJECT_DEPS_URL, {
@@ -595,33 +552,36 @@ if (command === 'alex') {
595
552
  uiSchema: uiSchema || null
596
553
  }
597
554
  });
598
- process.stdout.write(` \x1b[32mOK\x1b[0m\n`);
555
+ process.stdout.write(`\x1b[32m[OK]\x1b[0m\n`);
599
556
  } catch (err) {
600
- process.stdout.write(` \x1b[31mFAILED\x1b[0m\n`);
601
- console.error(` ⚠️ OS sync failed: ${err.message}`);
557
+ process.stdout.write(`\x1b[31m[FAILED]\x1b[0m\n`);
558
+ console.error(`\x1b[31m[Error] OS sync failed: ${err.message}\x1b[0m`);
602
559
  }
603
560
 
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`);
561
+ console.log('\x1b[90mIf you manually edit the native code, sync it to the Cloud OS:\x1b[0m');
562
+ console.log(`\x1b[33mpatch module\x1b[0m \x1b[36m${moduleName}\x1b[0m \x1b[33mandroid\x1b[0m \x1b[90m(or ios)\x1b[0m`);
563
+ console.log('\x1b[90mTo eradicate this module later, open a new terminal and type:\x1b[0m');
564
+ console.log(`\x1b[31mnpm run fleetbo rm\x1b[0m \x1b[36m${moduleName}\x1b[0m`);
565
+
566
+ if (totalTokens > 0) {
567
+ console.log(`\x1b[90m[Telemetry] Total tokens consumed for this forge: ${totalTokens}\x1b[0m\n`);
568
+ }
609
569
 
610
570
  } 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`);
571
+ console.log('\x1b[31m[Error] Alex replied, but source code could not be extracted.\x1b[0m\n');
612
572
  }
613
573
  } catch (error) {
614
574
  process.stdout.write('\r' + ' '.repeat(50) + '\r');
615
- console.error('\n\x1b[31m Alex Error:\x1b[0m ' + (error.response?.data?.message || error.message));
575
+ console.error('\x1b[31m[Alex Error]\x1b[0m ' + (error.response?.data?.message || error.message));
616
576
  }
617
577
  };
618
578
 
619
579
  // ============================================================
620
- // DÉMARRAGE DE LA SESSION INTERACTIVE ALEX
580
+ // START INTERACTIVE SESSION
621
581
  // ============================================================
622
582
 
623
583
  const startAlexSession = async () => {
624
- process.stdout.write('\x1b[33m🛡️ Alex is checking runtime state...\x1b[0m\r');
584
+ process.stdout.write('\x1b[33m[Alex] Checking runtime state...\x1b[0m\r');
625
585
  let attempts = 0;
626
586
  const maxAttempts = 5;
627
587
  let isReady = false;
@@ -653,7 +613,7 @@ if (command === 'alex') {
653
613
  }
654
614
 
655
615
  if (!isReady) {
656
- console.error('\n\x1b[31m⚠️ ENGINE OFFLINE:\x1b[0m Start Fleetbo runtime first: "npm run fleetbo" ');
616
+ console.error('\x1b[31m[ENGINE OFFLINE]\x1b[0m Start Fleetbo runtime first: "npm run fleetbo" ');
657
617
  console.error(`\x1b[90m(Ensure you are running the runtime for project: ${keyApp})\x1b[0m`);
658
618
  process.exit(1);
659
619
  }
@@ -661,21 +621,15 @@ if (command === 'alex') {
661
621
  process.stdout.write(' '.repeat(60) + '\r');
662
622
 
663
623
  if (!hasAiKey) {
664
- console.log('');
665
- console.log('\x1b[1m\x1b[33m AI Configuration Required\x1b[0m');
666
- console.log('');
624
+ console.log('\x1b[1m\x1b[33mAI Configuration Required\x1b[0m\n');
667
625
  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('');
626
+ console.log('Connect your own AI key to continue.\n');
670
627
  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('');
628
+ console.log('\x1b[32m[+]\x1b[0m Google AI \x1b[90m(Gemini Pro)\x1b[0m');
629
+ console.log('\x1b[36mhttps://aistudio.google.com/app/apikey\x1b[0m\n');
630
+ console.log('\x1b[33m[+]\x1b[0m Anthropic \x1b[90m(Claude Sonnet / Opus)\x1b[0m');
631
+ console.log('\x1b[36mhttps://console.anthropic.com/settings/keys\x1b[0m\n');
632
+ console.log('\x1b[90mClick the \x1b[32m[+]\x1b[90m button in the Terminal top-right bar\x1b[0m\n');
679
633
  process.exit(0);
680
634
  }
681
635
 
@@ -686,32 +640,27 @@ if (command === 'alex') {
686
640
 
687
641
  console.log('\x1b[90m┌─────────────────────────────────────────────────────────┐\x1b[0m');
688
642
  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');
643
+ 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
644
  console.log('\x1b[90m│ │\x1b[0m');
691
645
  console.log('\x1b[90m│\x1b[0m \x1b[90mYour JS stays the brain. I forge the metal.\x1b[0m \x1b[90m│\x1b[0m');
692
646
  console.log('\x1b[90m│ │\x1b[0m');
693
647
  console.log('\x1b[90m└─────────────────────────────────────────────────────────┘\x1b[0m');
694
648
 
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`);
649
+ console.log(`\x1b[32m[OK]\x1b[0m ${providerLabel} \x1b[90m· ${modelLabel}\x1b[0m`);
650
+ 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
651
 
699
- console.log('');
700
652
  console.log('\x1b[36mCAPABILITIES\x1b[0m');
701
653
  console.log('\x1b[90m─────────────────────────────────────────────────────\x1b[0m');
702
654
  console.log('\x1b[1mHardware\x1b[0m\x1b[90m Camera · Scanner · GPS · Biometrics\x1b[0m');
703
655
  console.log('\x1b[1mHigh-Perf\x1b[0m\x1b[90m Video Feed · Swipe Deck · Audio\x1b[0m');
704
656
  console.log('\x1b[1mSovereign\x1b[0m\x1b[90m Form + Photo + Save-to-Cloud\x1b[0m');
705
657
  console.log('\x1b[1mFleetbo View\x1b[0m\x1b[90m Full native tab (120 FPS)\x1b[0m');
706
- console.log('\x1b[90m─────────────────────────────────────────────────────\x1b[0m');
658
+ console.log('\x1b[90m─────────────────────────────────────────────────────\x1b[0m\n');
707
659
 
708
- console.log('');
709
660
  console.log('\x1b[36mCODE GENERATION SYNTAX\x1b[0m \x1b[90m(strict format required)\x1b[0m');
710
- console.log('');
711
661
  console.log('\x1b[90mFormat: \x1b[33m<verb>\x1b[0m module \x1b[36m<ModuleName>\x1b[0m');
712
662
  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('');
663
+ console.log('\x1b[90mExample: \x1b[0m\x1b[33mupdate\x1b[0m module \x1b[36mProfileManager\x1b[0m \x1b[90mwith a red button\x1b[0m\n');
715
664
 
716
665
  console.log('\x1b[32mAlex ❯\x1b[0m Describe your feature using the Compose panel...');
717
666
 
@@ -721,7 +670,7 @@ if (command === 'alex') {
721
670
  });
722
671
 
723
672
  rl.on('SIGINT', () => {
724
- console.log('\n\x1b[90m Alex session aborted (Ctrl+C).\x1b[0m');
673
+ console.log('\x1b[90mAlex session aborted (Ctrl+C).\x1b[0m');
725
674
  process.stdout.write('[ALEX_OFFLINE]\n');
726
675
  rl.close();
727
676
  process.exit(0);
@@ -732,7 +681,7 @@ if (command === 'alex') {
732
681
 
733
682
  const executePrompt = async (text) => {
734
683
  if (['exit', 'quit'].includes(text.toLowerCase())) {
735
- console.log('\n\x1b[90m Alex session closed.\x1b[0m');
684
+ console.log('\x1b[90mAlex session closed.\x1b[0m');
736
685
  process.stdout.write('[ALEX_OFFLINE]\n');
737
686
  rl.close();
738
687
  return;
@@ -740,9 +689,7 @@ if (command === 'alex') {
740
689
 
741
690
  if (text !== "") {
742
691
  isProcessing = true;
743
-
744
692
  await processAlexRequest(text);
745
-
746
693
  isProcessing = false;
747
694
  console.log('');
748
695
  }
@@ -781,16 +728,14 @@ if (command === 'alex') {
781
728
  else if (command === 'rm') {
782
729
  const moduleName = args[1];
783
730
  if (!moduleName) {
784
- console.error('\n\x1b[31mError: Module name required.\x1b[0m');
731
+ console.error('\x1b[31m[Error] Module name required.\x1b[0m');
785
732
  console.log('\x1b[90mUsage: npm run fleetbo rm [ModuleName]\x1b[0m\n');
786
733
  process.exit(1);
787
734
  }
788
735
 
789
- console.log(`\n\x1b[33m🗑️ Annihilating module: ${moduleName}...\x1b[0m`);
736
+ console.log(`\x1b[33m[Annihilation] Removing module: ${moduleName}...\x1b[0m`);
790
737
 
791
- // 1. Define physical paths
792
738
  const ktPath = path.join(process.cwd(), 'public', 'native', 'android', `${moduleName}.kt`);
793
- // AGNOSTIQUE — cherche .jsx (React) puis .vue (Vue)
794
739
  const jsxPath = path.join(process.cwd(), 'src', 'app', 'mocks', `${moduleName}.jsx`);
795
740
  const vuePath = path.join(process.cwd(), 'src', 'app', 'mocks', `${moduleName}.vue`);
796
741
  const mockPath = fs.existsSync(jsxPath) ? jsxPath : fs.existsSync(vuePath) ? vuePath : null;
@@ -798,28 +743,25 @@ else if (command === 'rm') {
798
743
 
799
744
  let actionsDone = 0;
800
745
 
801
- // 2. Eradicate Metal Engine (Kotlin)
802
746
  if (fs.existsSync(ktPath)) {
803
747
  fs.unlinkSync(ktPath);
804
- console.log(` \x1b[32m[Deleted]\x1b[0m Metal file (.kt) eradicated.`);
748
+ console.log(`\x1b[32m[Deleted]\x1b[0m Metal file (.kt) eradicated.`);
805
749
  actionsDone++;
806
750
  }
807
751
 
808
- // 3. Eradicate Virtual Twin (Mock JSX or Vue)
809
752
  if (mockPath) {
810
753
  fs.unlinkSync(mockPath);
811
- console.log(` \x1b[32m[Deleted]\x1b[0m Virtual Twin (${mockExt}) eradicated.`);
754
+ console.log(`\x1b[32m[Deleted]\x1b[0m Virtual Twin (${mockExt}) eradicated.`);
812
755
  actionsDone++;
813
756
  }
814
757
 
815
- // 4. Disinfect System Core (App.jsx)
816
758
  const unrouted = removeRouteFromAppJs(moduleName);
817
759
  if (unrouted) actionsDone++;
818
760
 
819
761
  if (actionsDone === 0) {
820
- console.log(`\n\x1b[31m⚠️ No trace of module "${moduleName}" found in the OS.\x1b[0m\n`);
762
+ console.log(`\x1b[31m[Warning] No trace of module "${moduleName}" found in the OS.\x1b[0m\n`);
821
763
  } else {
822
- console.log(`\n\x1b[32m Module ${moduleName} successfully eradicated from the OS.\x1b[0m\n`);
764
+ console.log(`\x1b[32mModule ${moduleName} successfully eradicated from the OS.\x1b[0m\n`);
823
765
  }
824
766
  }
825
767
 
@@ -828,21 +770,17 @@ else if (command === 'rm') {
828
770
  // ============================================
829
771
  else if (command === 'android' || command === 'ios') {
830
772
 
831
- // DÉBUT DE LA PROTECTION (Fonction Async Immédiate)
832
- // Cela garantit que le code fonctionne partout, même via 'require()'
833
773
  (async () => {
834
774
 
835
- // 🛑 INTERCEPTION IOS : BLOQUAGE NET (MAINTENANCE/BETA)
836
775
  if (command === 'ios') {
837
- console.log(`\n\x1b[36mFLEETBO IOS PROPULSION\x1b[0m`);
776
+ console.log(`\x1b[36m[FLEETBO IOS PROPULSION]\x1b[0m`);
838
777
  console.log(`\x1b[33m[0/3] Initializing Neural Uplink...\x1b[0m`);
839
778
 
840
- // Ce 'await' est maintenant sécurisé
841
779
  await new Promise(r => setTimeout(r, 800));
842
780
 
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`);
781
+ console.log(`\x1b[31m[PROPULSION ABORTED] iOS Frequency Restricted.\x1b[0m`);
782
+ console.log(`\x1b[90mThis module is currently reserved for Vanguard Pilots (Closed Beta).\x1b[0m`);
783
+ console.log(`\x1b[90mPlease engage propulsion on Android frequency for now.\x1b[0m\n`);
846
784
 
847
785
  process.exit(1);
848
786
  }
@@ -853,7 +791,6 @@ else if (command === 'android' || command === 'ios') {
853
791
  const extension = platform === 'android' ? '.kt' : '.swift';
854
792
  const nativePath = path.join(process.cwd(), nativeDir);
855
793
 
856
- // Vérification des modules natifs
857
794
  let hasNativeFiles = false;
858
795
  let nativeFileCount = 0;
859
796
  if (fs.existsSync(nativePath)) {
@@ -864,7 +801,7 @@ else if (command === 'android' || command === 'ios') {
864
801
  }
865
802
 
866
803
  if (!hasNativeFiles) {
867
- console.log(`\n\x1b[31m⚠️ ENGINE INCOMPLETE:\x1b[0m No native blueprints detected for \x1b[1m${platform.toUpperCase()}\x1b[0m.`);
804
+ console.log(`\x1b[31m[ENGINE INCOMPLETE]\x1b[0m No native blueprints detected for \x1b[1m${platform.toUpperCase()}\x1b[0m.`);
868
805
  console.log(`\x1b[90mAlex must architect at least one ${extension} module before deployment.\x1b[0m`);
869
806
  console.log(`\x1b[90mRun: npm run fleetbo alex\x1b[0m\n`);
870
807
  process.exit(1);
@@ -872,23 +809,18 @@ else if (command === 'android' || command === 'ios') {
872
809
 
873
810
  const targetUrl = platform === 'android' ? ANDROID_BUILD_URL : IOS_BUILD_URL;
874
811
 
875
- console.log(`\n\x1b[36mFLEETBO ${platform.toUpperCase()} PROPULSION\x1b[0m`);
876
- console.log(`\x1b[90m ${nativeFileCount} fleetbo module(s) detected\x1b[0m\n`);
812
+ console.log(`\x1b[36m[FLEETBO ${platform.toUpperCase()} PROPULSION]\x1b[0m`);
813
+ console.log(`\x1b[90m${nativeFileCount} fleetbo module(s) detected\x1b[0m\n`);
877
814
 
878
815
  try {
879
- // ==========================================================
880
- // PRE-FLIGHT CHECK QUOTAS & TIER
881
- // ==========================================================
882
816
  process.stdout.write(`\x1b[33m[0/3]\x1b[0m Checking Propulsion Access... `);
883
817
  try {
884
- // On envoie le signal 'x-preflight' pour tester les droits sans builder
885
818
  await axios.post(targetUrl, {}, {
886
819
  headers: {
887
820
  'x-project-id': projectId,
888
821
  'x-preflight': 'true'
889
822
  }
890
823
  });
891
- // Si ça passe (200 OK), c'est un Senior ou un Junior autorisé (si vous changez d'avis)
892
824
  process.stdout.write(`\x1b[32mOK (Senior Pilot)\x1b[0m\n\n`);
893
825
 
894
826
  } catch (preflightError) {
@@ -896,27 +828,21 @@ else if (command === 'android' || command === 'ios') {
896
828
 
897
829
  const errData = preflightError.response?.data;
898
830
 
899
- // 🛑 1. INTERCEPTION SPÉCIFIQUE JUNIOR
900
- // C'est ici qu'on lit le code renvoyé par index.js
901
831
  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
832
  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
833
+ console.log(`\x1b[31m[ACCESS DENIED] JUNIOR PILOT DETECTED\x1b[0m`);
834
+ console.log(`\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\n`);
835
+ console.log(`\x1b[33mThis feature is locked for Junior Pilots.\x1b[0m`);
836
+ console.log(`\x1b[32mUpgrade to Senior on fleetbo.io to unlock Propulsion.\x1b[0m\n`);
837
+ process.exit(1);
910
838
  }
911
839
 
912
- // 2. Gestion des autres erreurs (Quota Senior dépassé, Serveur HS, etc.)
913
840
  if (errData && errData.error) {
914
841
  throw new Error(errData.error);
915
842
  }
916
843
  throw preflightError;
917
844
  }
918
845
 
919
- // Étape 1: Build React
920
846
  console.log(`\x1b[33m[1/3]\x1b[0m Synthesizing Fleetbo Core Logic...`);
921
847
  execSync('npm run build', { stdio: 'inherit' });
922
848
 
@@ -927,8 +853,7 @@ else if (command === 'android' || command === 'ios') {
927
853
  throw new Error(`Build directory not found: ${buildDir}`);
928
854
  }
929
855
 
930
- // Étape 2: Créer le ZIP
931
- console.log(`\n\x1b[33m[2/3]\x1b[0m Packaging bundle + fleetbo modules...`);
856
+ console.log(`\x1b[33m[2/3]\x1b[0m Packaging bundle + fleetbo modules...`);
932
857
 
933
858
  const zipBuffer = await new Promise((resolve, reject) => {
934
859
  const chunks = [];
@@ -949,10 +874,9 @@ else if (command === 'android' || command === 'ios') {
949
874
  });
950
875
 
951
876
  const sizeMB = (zipBuffer.length / 1024 / 1024).toFixed(2);
952
- console.log(` \x1b[32m✓\x1b[0m Bundle ready: ${sizeMB} MB`);
877
+ console.log(`\x1b[32m[Ready]\x1b[0m Bundle ready: ${sizeMB} MB`);
953
878
 
954
- // Étape 3: Upload
955
- console.log(`\n\x1b[33m[3/3]\x1b[0m Uploading to Fleetbo OS...`);
879
+ console.log(`\x1b[33m[3/3]\x1b[0m Uploading to Fleetbo OS...`);
956
880
  await showEnergyTransfer();
957
881
 
958
882
  let uploadResponse;
@@ -975,28 +899,28 @@ else if (command === 'android' || command === 'ios') {
975
899
  }
976
900
 
977
901
  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
902
  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`);
903
+ console.log(`\x1b[32m[SUCCESS] ${platform.toUpperCase()} PROPULSION SUCCESSFUL\x1b[0m`);
904
+ console.log(`\x1b[32m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
905
+ console.log(`\x1b[90mDeployment ID: ${uploadResponse.data.deploymentId || 'N/A'}\x1b[0m`);
906
+ console.log(`\x1b[90m${uploadResponse.data.message || 'Complete.'}\x1b[0m\n`);
983
907
  } else {
984
908
  throw new Error(uploadResponse.data?.error || 'Unknown logical error from Factory');
985
909
  }
986
910
 
987
911
  } catch (error) {
988
- console.log(`\n\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
989
- console.log(`\x1b[31m PROPULSION FAILED\x1b[0m`);
912
+ console.log(`\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
913
+ console.log(`\x1b[31m[Propulsion Failed]\x1b[0m`);
990
914
  console.log(`\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
991
915
 
992
- console.error(`\x1b[31m Error:\x1b[0m ${error.message}`);
916
+ console.error(`\x1b[31m[Error]\x1b[0m ${error.message}`);
993
917
 
994
918
  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.`);
919
+ console.log(`\x1b[33m[Tip]\x1b[0m Upgrade to Senior Pilot for more builds.`);
996
920
  } 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.`);
921
+ console.log(`\x1b[33m[Tip]\x1b[0m Run "npm run fleetbo alex" to create native modules first.`);
998
922
  } 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.`);
923
+ console.log(`\x1b[33m[Tip]\x1b[0m Your free sprint is over. Upgrade to Senior Pilot on fleetbo.io.`);
1000
924
  }
1001
925
  console.log('');
1002
926
  process.exit(1);
@@ -1012,7 +936,7 @@ else if (['page', 'g', 'generate'].includes(command)) {
1012
936
  try {
1013
937
  require(pageGeneratorPath);
1014
938
  } catch (e) {
1015
- console.error('\x1b[31m Page Generator Error:\x1b[0m', e.message);
939
+ console.error('\x1b[31m[Page Generator Error]\x1b[0m', e.message);
1016
940
  process.exit(1);
1017
941
  }
1018
942
  }
@@ -1053,10 +977,10 @@ else {
1053
977
  async function cleanupAndExit(code = 0) {
1054
978
  if (isExiting) return;
1055
979
  isExiting = true;
1056
- console.log('\n\x1b[33m[Fleetbo] 🛑 Stopping environment & Cleaning Uplink...\x1b[0m');
980
+ console.log('\x1b[33m[Fleetbo] Stopping environment & Cleaning Uplink...\x1b[0m');
1057
981
  try {
1058
982
  await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl: '', tester: testerEmail });
1059
- console.log('\x1b[32m[Fleetbo] Network status reset to offline.\x1b[0m');
983
+ console.log('\x1b[32m[Fleetbo] Network status reset to offline.\x1b[0m');
1060
984
  } catch (e) {
1061
985
  console.error('[Fleetbo] Network cleanup warning:', e.message);
1062
986
  }
@@ -1066,7 +990,6 @@ else {
1066
990
  process.exit(code);
1067
991
  }
1068
992
 
1069
- // 🪟 WINDOWS FIX : capture Ctrl+C via readline pour éviter l'invite "O/N"
1070
993
  if (process.platform === 'win32') {
1071
994
  const rlWin = require('readline').createInterface({ input: process.stdin, output: process.stdout });
1072
995
  rlWin.on('SIGINT', () => cleanupAndExit(0));
@@ -1078,31 +1001,30 @@ else {
1078
1001
  async function syncFirebase(keyApp, networkUrl, testerEmail) {
1079
1002
  try {
1080
1003
  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 -------------------------------------------------------------`);
1004
+ console.log('\x1b[32mEngine started successfully\x1b[0m');
1005
+ console.log(`\x1b[32mFleetbo OS ❯\x1b[0m -------------------------------------------------------------`);
1083
1006
  console.log(`\x1b[32mFleetbo OS ❯\x1b[0m \x1b[1mProject [${keyApp}] running in OS\x1b[0m`);
1084
1007
  console.log('\x1b[32mFleetbo OS ❯\x1b[0m You can now start coding and previewing.');
1085
1008
  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`);
1009
+ console.log(`\x1b[34mPilot Instruction ❯\x1b[0m Return to the Workspace. The Engine is ready for your orders.\n`);
1087
1010
  } catch (err) {
1088
1011
  console.error(`\x1b[31mFleetbo OS ❯\x1b[0m Sync Error: ${err.message}`);
1089
1012
  }
1090
1013
  }
1091
1014
 
1092
1015
  async function runDevEnvironment() {
1093
- console.log(`[Fleetbo] Initializing Universal Dev Environment...`);
1016
+ console.log(`[Fleetbo] Initializing Universal Dev Environment...`);
1094
1017
 
1095
1018
  killNetworkService();
1096
- killProcessOnPort(PORT); // On tue le 3000 par précaution, au cas où
1019
+ killProcessOnPort(PORT);
1097
1020
 
1098
1021
  if (!testerEmail) {
1099
- console.error('\x1b[31mError: FLEETBO_APP_TESTER_EMAIL missing in .env\x1b[0m');
1022
+ console.error('\x1b[31m[Error] FLEETBO_APP_TESTER_EMAIL missing in .env\x1b[0m');
1100
1023
  process.exit(1);
1101
1024
  }
1102
1025
 
1103
1026
  const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
1104
1027
 
1105
- // Lancement agnostique du serveur de dev (React, Vue, etc.)
1106
1028
  const devServer = spawn(`${npmCmd} run dev --silent -- --host 127.0.0.1 --port ${PORT}`, {
1107
1029
  stdio: ['ignore', 'pipe', 'pipe'],
1108
1030
  shell: true,
@@ -1115,12 +1037,11 @@ else {
1115
1037
  devServer.stderr.pipe(process.stderr);
1116
1038
 
1117
1039
  let connectionStarted = false;
1118
- let detectedPort = PORT; // 3000 par défaut
1040
+ let detectedPort = PORT;
1119
1041
 
1120
1042
  devServer.stdout.on('data', (data) => {
1121
1043
  const output = data.toString();
1122
1044
 
1123
- // FILTRE ANTI-PLOMBERIE FLEETBO
1124
1045
  const lines = output.split('\n');
1125
1046
  const forbiddenTerms = [
1126
1047
  'Attempting to bind to HOST', 'If this was unintentional', 'Learn more here:',
@@ -1137,22 +1058,17 @@ else {
1137
1058
  process.stdout.write(filteredOutput + '\n');
1138
1059
  }
1139
1060
 
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
1061
  const portMatch = output.match(/http:\/\/(?:localhost|127\.0\.0\.1):(\d+)/);
1145
1062
 
1146
1063
  if (portMatch) {
1147
- detectedPort = portMatch[1]; // Capture le port final choisi par Vite
1064
+ detectedPort = portMatch[1];
1148
1065
 
1149
- // On lance le tunnel Cloudflare UNIQUEMENT sur ce port définitif
1150
1066
  if (!connectionStarted) {
1151
1067
  connectionStarted = true;
1152
1068
 
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...`);
1069
+ console.log('\x1b[33mFleetbo OS ❯\x1b[0m ---------------------------------------------------');
1070
+ console.log(`\x1b[33mFleetbo OS ❯\x1b[0m Establishing Secure Uplink...`);
1071
+ console.log(`\x1b[33mFleetbo OS ❯\x1b[0m Please wait for the green message...`);
1156
1072
  console.log('\x1b[33mFleetbo OS ❯\x1b[0m ---------------------------------------------------');
1157
1073
 
1158
1074
  const MAX_UPLINK_RETRIES = 5;
@@ -1165,10 +1081,9 @@ else {
1165
1081
  const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
1166
1082
 
1167
1083
  if (attempt > 0) {
1168
- console.log(`\x1b[33m[Fleetbo] Uplink reconnection ${attempt}/${MAX_UPLINK_RETRIES - 1}...\x1b[0m`);
1084
+ console.log(`\x1b[33m[Fleetbo] Uplink reconnection ${attempt}/${MAX_UPLINK_RETRIES - 1}...\x1b[0m`);
1169
1085
  }
1170
1086
 
1171
- // LE TUNNEL CLOUDFLARE UTILISE LE PORT DÉTECTÉ DYNAMIQUEMENT !
1172
1087
  const uplinkCommand = `${npxCmd} -y cloudflared tunnel --url http://127.0.0.1:${detectedPort} --http-host-header 127.0.0.1:${detectedPort}`;
1173
1088
  uplinkProcess = spawn(uplinkCommand, { shell: true });
1174
1089
 
@@ -1189,7 +1104,7 @@ else {
1189
1104
 
1190
1105
  uplinkProcess.on('error', () => {
1191
1106
  if (uplinkFound) return;
1192
- console.error(`\x1b[31m[Fleetbo] ⚠️ Uplink Connection failed to establish.\x1b[0m`);
1107
+ console.error(`\x1b[31m[Fleetbo] Uplink Connection failed to establish.\x1b[0m`);
1193
1108
  });
1194
1109
 
1195
1110
  uplinkProcess.on('close', () => {
@@ -1197,10 +1112,10 @@ else {
1197
1112
  const nextAttempt = attempt + 1;
1198
1113
  if (nextAttempt < MAX_UPLINK_RETRIES) {
1199
1114
  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`);
1115
+ console.log(`\x1b[33m[Fleetbo] Uplink interrupted. Fleetbo OS retrying in ${delay}s... (${nextAttempt}/${MAX_UPLINK_RETRIES - 1})\x1b[0m`);
1201
1116
  setTimeout(() => startUplink(nextAttempt), delay * 1000);
1202
1117
  } else {
1203
- console.error(`\x1b[31m[Fleetbo] Secure Uplink could not be established.\x1b[0m`);
1118
+ console.error(`\x1b[31m[Fleetbo] Secure Uplink could not be established.\x1b[0m`);
1204
1119
  }
1205
1120
  });
1206
1121
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbo-cockpit-cli",
3
- "version": "1.0.218",
3
+ "version": "1.0.220",
4
4
  "description": "Fleetbo CLI - Build native mobile apps with React",
5
5
  "author": "Fleetbo",
6
6
  "license": "MIT",