fleetbo-cockpit-cli 1.0.72 → 1.0.73

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 +134 -51
  2. package/package.json +1 -1
package/cli.js CHANGED
@@ -146,9 +146,10 @@ const showEnergyTransfer = async () => {
146
146
 
147
147
  // Détecte TOUS les mots en PascalCase (ex: GuestCreator, CameraModule, Tab2)
148
148
  const extractPotentialModules = (text) => {
149
- const regex = /\b[A-Z][a-zA-Z0-9_]{2,}\b/g;
149
+ // Regex stricte : Majuscule + minuscules + Majuscule (ex: ProfileCreator, UserConfig)
150
+ const regex = /\b[A-Z][a-z]+[A-Z][a-zA-Z0-9_]*\b/g;
150
151
  const matches = text.match(regex) || [];
151
- return [...new Set(matches)]; // Dédoublonne les résultats
152
+ return [...new Set(matches)];
152
153
  };
153
154
 
154
155
 
@@ -219,8 +220,8 @@ if (command === 'alex') {
219
220
  return;
220
221
  }
221
222
 
222
- // 📋 INTERCEPTION : LISTER LES MODULES
223
- const isListingRequest = /^(liste|list|quels modules|montre les modules)/i.test(prompt);
223
+ // 📋 INTERCEPTION: LIST MODULES
224
+ const isListingRequest = /^(liste|list|quels modules|montre les modules|show modules)/i.test(prompt);
224
225
  if (isListingRequest) {
225
226
  process.stdout.write(` \x1b[90m🔍 Scanning OS Cache...\x1b[0m\n`);
226
227
  const cacheRes = await getModuleCache({ projectId, moduleName: null });
@@ -232,7 +233,7 @@ if (command === 'alex') {
232
233
  console.log(` ${metalColor}■\x1b[0m \x1b[1m${m.moduleName}\x1b[0m \x1b[90m(${m.platform})\x1b[0m`);
233
234
  });
234
235
  } else {
235
- console.log(`\n \x1b[90mAucun module trouvé dans l'infrastructure de ce projet.\x1b[0m`);
236
+ console.log(`\n \x1b[90mNo modules found in the infrastructure of this project.\x1b[0m`);
236
237
  }
237
238
  return;
238
239
  }
@@ -240,33 +241,70 @@ if (command === 'alex') {
240
241
  console.log('\x1b[33m🧠 Alex is thinking...\x1b[0m');
241
242
 
242
243
  try {
243
- // --- SYSTÈME DE MÉMOIRE (SMART CACHE SCANNER) ---
244
+ // --- MEMORY SYSTEM (SMART CACHE SCANNER V3 - SOUVERAINETÉ DU MÉTAL) ---
244
245
  let contextInjection = "";
245
246
  const potentialModules = extractPotentialModules(prompt);
247
+
248
+ let targetModuleContext = "";
249
+ let referenceContexts = "";
246
250
 
247
- for (const modName of potentialModules) {
248
- process.stdout.write(` \x1b[90m🔍 Checking os cache for ${modName}...\x1b[0m`);
251
+ for (let modName of potentialModules) {
252
+ let isReferenceOnly = false;
253
+
254
+ // 🟢 LE DÉTECTEUR D'INSPIRATION
255
+ if (modName.endsWith('Ref')) {
256
+ isReferenceOnly = true;
257
+ modName = modName.replace('Ref', '');
258
+ } else if (modName.endsWith('Schema')) {
259
+ isReferenceOnly = true;
260
+ modName = modName.replace('Schema', '');
261
+ }
262
+
263
+ process.stdout.write(` \x1b[90m🔍 Checking OS cache for ${modName}...\x1b[0m`);
249
264
  const cache = await getModuleCache({ projectId, moduleName: modName });
250
265
 
251
266
  if (cache.found) {
252
267
  process.stdout.write(` \x1b[32mFOUND METAL\x1b[0m\n`);
253
268
 
254
- const intent = getContextIntent(prompt);
255
- const contextTitle = intent === "MODIFICATION"
256
- ? "MÉTAL EXISTANT MODIFIER)"
257
- : "MÉTAL DE RÉFÉRENCE (POUR PARITÉ DES DONNÉES)";
258
-
259
- contextInjection = `\n--- CONTEXTE SOUVERAIN : ${contextTitle} (${modName}) ---\nDOGME: Le Métal est la source de vérité absolue. Le Mock n'est qu'une illusion.\nTu DOIS analyser ce code Natif pour comprendre EXACTEMENT comment les données ont été structurées, nommées (clés JSON) et sauvegardées.\n\n[CODE NATIF EXISTANT]\n${cache.module.code}\n--- FIN DU CONTEXTE ---\n`;
269
+ // NOUVEAU BLOC : INJECTION DE LA DOUBLE MÉMOIRE
270
+ let memoryScript = "";
271
+ if (cache.module.dataSchema) memoryScript += `\n[SCRIPT MÉMOIRE DONNÉES]\n${cache.module.dataSchema}\n`;
272
+ if (cache.module.uiSchema) memoryScript += `\n[SCRIPT MÉMOIRE UI NATIF]\n${cache.module.uiSchema}\n`;
260
273
 
261
- prompt = contextInjection + "\n\n[INSTRUCTION DU PILOTE]\n" + prompt;
262
- break;
274
+ if (!memoryScript) memoryScript = `\n[SCRIPT MÉMOIRE DU MODULE ${modName}]\nAucun schéma enregistré pour ce module.\n`;
275
+
276
+ if (isReferenceOnly) {
277
+ // 🚨 CAS A : INSPIRATION (Lecture seule)
278
+ referenceContexts += `\n--- CONTEXTE : MODULE DE RÉFÉRENCE (${modName}) ---\nDOGME : Ne modifie pas ce module (Lecture seule). Tu dois l'utiliser comme modèle. Aligne-toi sur ses Scripts Mémoires (Données et/ou UI) et sur son Code Natif en fonction de ce que le Pilote te demande d'imiter.\n${memoryScript}\n[CODE NATIF DE RÉFÉRENCE]\n${cache.module.code}\n`;
279
+ } else if (!targetModuleContext) {
280
+ // 🚨 CAS B : CIBLE PRINCIPALE (Modification)
281
+ // LE MOCK EST BANI ! Le Métal est la seule source de vérité.
282
+ const intent = getContextIntent(prompt);
283
+ if (intent === "MODIFICATION") {
284
+ targetModuleContext = `\n--- CONTEXTE : MÉTAL EXISTANT À MODIFIER (${modName}) ---\nDOGME: Tu dois modifier ce code Natif. Ensuite, tu forgeras un Mock JSX entièrement neuf basé UNIQUEMENT sur ton nouveau code Natif.\n${memoryScript}\n[CODE NATIF EXISTANT]\n${cache.module.code}\n--- FIN DU CONTEXTE ---\n`;
285
+ } else {
286
+ targetModuleContext = `\n--- CONTEXTE : BASE DE TRAVAIL (${modName}) ---\n${memoryScript}\n`;
287
+ }
288
+ }
263
289
  } else {
264
290
  process.stdout.write(` \x1b[31mNOT FOUND\x1b[0m\n`);
265
291
  }
266
292
  }
267
- // --- FIN MODIFICATION MÉMOIRE ---
268
293
 
269
- const result = await axios.post(ALEX_ENGINE_URL, { prompt, projectType: 'android' }, {
294
+ contextInjection = referenceContexts + targetModuleContext;
295
+ if (contextInjection) {
296
+ prompt = contextInjection + "\n\n[INSTRUCTION DU PILOTE]\n" + prompt;
297
+ }
298
+ // --- END MEMORY MODIFICATION ---
299
+
300
+ // 🟢 NEW: Real-time timestamp injection
301
+ const now = new Date();
302
+ // Clean format: YYYY-MM-DD at HH:MM:SS
303
+ const exactTime = now.toISOString().split('T')[0] + ' at ' + now.toTimeString().split(' ')[0];
304
+
305
+ 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.]`;
306
+
307
+ const result = await axios.post(ALEX_ENGINE_URL, { prompt: promptWithTime, projectType: 'android' }, {
270
308
  headers: { 'x-project-id': projectId }
271
309
  });
272
310
 
@@ -276,6 +314,12 @@ if (command === 'alex') {
276
314
  try { aiData = JSON.parse(aiData); } catch (_) {}
277
315
  }
278
316
 
317
+ // 🟢 DISPLAY REASONING IN TERMINAL
318
+ if (aiData.thinking_process) {
319
+ // Show start of reasoning in gray for info
320
+ console.log(` \x1b[90m🧠 Alex Analysis: ${aiData.thinking_process.substring(0, 150)}...\x1b[0m`);
321
+ }
322
+
279
323
  process.stdout.write('\x1b[A\r' + ' '.repeat(50) + '\r');
280
324
 
281
325
  if (aiData.status === 'quota_exceeded') {
@@ -312,21 +356,21 @@ if (command === 'alex') {
312
356
  const formattedMsg = wrapText(rawMsg, 85);
313
357
  console.log('\x1b[32mAlex ❯\x1b[0m ' + formattedMsg);
314
358
 
315
- if (aiData.remainingConsultations !== undefined) {
316
- const remaining = aiData.remainingConsultations;
317
- const limit = aiData.consultationLimit || 7;
318
- const tierLabel = aiData.tier === 'senior' ? 'SENIOR' : aiData.tier === 'expert' ? 'EXPERT' : 'JUNIOR';
319
- const percent = Math.round((remaining / limit) * 100);
320
- const energyColor = percent > 20 ? '\x1b[32m' : '\x1b[31m';
321
- console.log(`\n\x1b[36m⚡ Architect Fuel:\x1b[0m ${energyColor}${percent}%\x1b[0m (${remaining}/${limit} instructions left) [${tierLabel}]\n`);
322
- }
323
359
  }
324
360
 
325
- // --- C'EST ICI QUE LES FICHIERS SONT CRÉÉS ---
361
+ // --- FILE CREATION LOGIC ---
326
362
  if (aiData.status === 'success' && aiData.moduleData) {
327
- const { fileName, code, mockFileName, mockCode, moduleName, instructions, config_offload } = aiData.moduleData;
363
+ let { fileName, code, mockFileName, mockCode, moduleName, instructions, config_offload, dataSchema, uiSchema } = aiData.moduleData;
364
+
365
+ // 🛡️ ANTI-DUMP SHIELD (Prevents terminal flooding)
366
+ if (moduleName) {
367
+ // Cleanup module name
368
+ moduleName = moduleName.split('\n')[0].replace(/["'{}]/g, '').trim();
369
+ if (moduleName.length > 40) moduleName = moduleName.substring(0, 40) + "...";
370
+ }
371
+
328
372
  console.log(` \x1b[90m Architecting: ${moduleName}\x1b[0m`);
329
-
373
+
330
374
  const writeFile = (dir, name, content) => {
331
375
  const fullPath = path.join(process.cwd(), dir);
332
376
  const filePath = path.join(fullPath, name);
@@ -360,7 +404,7 @@ if (command === 'alex') {
360
404
  }
361
405
  }
362
406
 
363
- // --- SYNCHRONISATION DU KERNEL ---
407
+ // --- KERNEL SYNCHRONIZATION ---
364
408
  const depsCount = config_offload?.dependencies?.length || 0;
365
409
  process.stdout.write(` \x1b[33m[Cloud Inject]\x1b[0m Archiving ${moduleName} to OS (${depsCount} libs)...`);
366
410
 
@@ -374,7 +418,9 @@ if (command === 'alex') {
374
418
  code: code,
375
419
  mockFileName: mockFileName,
376
420
  mockCode: mockCode,
377
- config_offload: config_offload || { dependencies: [], permissions: [] }
421
+ config_offload: config_offload || { dependencies: [], permissions: [] },
422
+ dataSchema: dataSchema || null, // 👈 LA LIGNE MAGIQUE
423
+ uiSchema: uiSchema || null
378
424
  }
379
425
  });
380
426
  process.stdout.write(` \x1b[32mOK\x1b[0m\n`);
@@ -382,9 +428,18 @@ if (command === 'alex') {
382
428
  process.stdout.write(` \x1b[31mFAILED\x1b[0m\n`);
383
429
  console.error(` ⚠️ OS sync failed: ${err.message}`);
384
430
  }
431
+ // 🟢 LE FUEL EST DÉPLACÉ ICI (TOUTE FIN DU TRY)
432
+ if (aiData.remainingConsultations !== undefined) {
433
+ const remaining = aiData.remainingConsultations;
434
+ const limit = aiData.consultationLimit || 7;
435
+ const tierLabel = aiData.tier.toUpperCase();
436
+ const percent = Math.round((remaining / limit) * 100);
437
+ const energyColor = percent > 20 ? '\x1b[32m' : '\x1b[31m';
438
+ console.log(`\n\x1b[36m⚡ Architect Fuel:\x1b[0m ${energyColor}${percent}%\x1b[0m (${remaining}/${limit} instructions left) [${tierLabel}]\n`);
439
+ }
385
440
  } else if (aiData.status === 'success' && !aiData.moduleData) {
386
- // SÉCURITÉ : Si Alex s'emmêle les pinceaux et renvoie un mauvais format JSON
387
- console.log(`\n\x1b[31m⚠️ Erreur : Alex a répondu, mais le code source n'a pas pu être extrait. Réessayez la commande.\x1b[0m\n`);
441
+ // SAFETY: If formatting is broken
442
+ console.log(`\n\x1b[31m⚠️ Error: Alex replied, but source code could not be extracted. Try the command again.\x1b[0m\n`);
388
443
  }
389
444
  } catch (error) {
390
445
  process.stdout.write('\r' + ' '.repeat(50) + '\r');
@@ -426,25 +481,25 @@ if (command === 'alex') {
426
481
 
427
482
  process.stdout.write(' '.repeat(60) + '\r');
428
483
 
429
- // 1. IDENTITÉ
484
+ // 1. IDENTITY
430
485
  console.log('\n\x1b[32m🤖 Alex is online.\x1b[0m');
431
486
  console.log('\x1b[90m Your JS stays the brain. I forge the native muscle.\x1b[0m');
432
487
 
433
- // 2. CE QUE JE FORGE
488
+ // 2. FORGE CAPABILITIES
434
489
  console.log('\n\x1b[36m⚡ WHAT I CAN FORGE:\x1b[0m');
435
490
  console.log('');
436
491
  console.log(' \x1b[1m📷 Hardware\x1b[0m\x1b[90m Camera, Scanner, GPS, Biometrics, Sensors\x1b[0m');
437
492
  console.log(' \x1b[1m🎬 High-Perf\x1b[0m\x1b[90m Infinite Feeds, Video Players, Swipe Decks\x1b[0m');
438
493
  console.log(' \x1b[1m🏗️ Sovereign\x1b[0m\x1b[90m Full screens: form + photo + save-to-cloud\x1b[0m');
439
494
 
440
- // 3. LA COLLABORATION
495
+ // 3. COLLABORATION
441
496
  console.log('\n\x1b[36m💡 TELL ME "WHAT + WHY":\x1b[0m');
442
497
  console.log('\x1b[90m I will analyze your need and recommend the perfect module to forge.\x1b[0m');
443
498
  console.log('');
444
499
  console.log(' \x1b[33m"I need a camera [WHAT] to scan receipts for my expense tracker [WHY]"\x1b[0m');
445
500
  console.log(' \x1b[33m"I need a form [WHAT] to add products with photos to my catalog [WHY]"\x1b[0m');
446
501
 
447
- // 4. LA PRISE DE COMMANDE
502
+ // 4. READINESS
448
503
  console.log('\n\x1b[32mAlex ❯\x1b[0m I am ready. Describe your feature, and I will architect the solution.');
449
504
  console.log('');
450
505
 
@@ -481,7 +536,7 @@ if (command === 'alex') {
481
536
  inputBuffer = "";
482
537
 
483
538
  if (finalPrompt.length > 1000) {
484
- console.log(`\n\x1b[31m⛔ [Alex Safety] Mission rejetée : Taille excessive (${finalPrompt.length}/1000 caractères).\x1b[0m`);
539
+ console.log(`\n\x1b[31m⛔ [Alex Safety] Mission rejected: Excessive size (${finalPrompt.length}/1000 characters).\x1b[0m`);
485
540
  rl.setPrompt(`\x1b[34m${dynamicUsername} ❯ \x1b[0m`);
486
541
  rl.prompt();
487
542
  return;
@@ -796,13 +851,13 @@ else {
796
851
  try {
797
852
  await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl, tester: testerEmail });
798
853
  console.log('\n\x1b[32mEngine started successfully\x1b[0m');
799
- console.log(`\x1b[32m[Fleetbo]\x1b[0m -------------------------------------------------------------`);
800
- console.log('\x1b[32m[Fleetbo] \x1b[1mGO GO GO ! FLEETBO COCKPIT IS READY\x1b[0m');
801
- console.log('\x1b[32m[Fleetbo] You can now start coding and previewing in Studio. 🚀\x1b[0m');
802
- console.log(`\x1b[32m[Fleetbo]\x1b[0m -------------------------------------------------------------`);
803
- console.log(`\x1b[34mPilot Instruction ❯\x1b[0m Switch to your Fleetbo Cockpit tab to begin.\n`);
854
+ console.log(`\x1b[32mFleetbo OS ❯\x1b[0m -------------------------------------------------------------`);
855
+ console.log('\x1b[32mFleetbo OS ❯\x1b[0m \x1b[1mGO GO GO ! OS IS READY\x1b[0m');
856
+ console.log('\x1b[32mFleetbo OS ❯\x1b[0m You can now start coding and previewing. 🚀');
857
+ console.log(`\x1b[32mFleetbo OS ❯\x1b[0m -------------------------------------------------------------`);
858
+ console.log(`\x1b[34mPilot Instruction ❯\x1b[0m Return to the Workspace. The Engine is ready for your orders.\n`);
804
859
  } catch (err) {
805
- console.error(`[Fleetbo] Sync Error: ${err.message}`);
860
+ console.error(`\x1b[31mFleetbo OS ❯\x1b[0m Sync Error: ${err.message}`);
806
861
  }
807
862
  }
808
863
 
@@ -839,7 +894,7 @@ else {
839
894
  }
840
895
  });
841
896
 
842
- devServer.stdout.pipe(process.stdout);
897
+ //devServer.stdout.pipe(process.stdout);
843
898
  devServer.stderr.pipe(process.stderr);
844
899
 
845
900
  let connectionStarted = false;
@@ -847,13 +902,39 @@ else {
847
902
  devServer.stdout.on('data', (data) => {
848
903
  const output = data.toString();
849
904
 
905
+ // 🛡️ FILTRE ANTI-PLOMBERIE FLEETBO
906
+ const lines = output.split('\n');
907
+ const forbiddenTerms = [
908
+ 'Attempting to bind to HOST',
909
+ 'If this was unintentional',
910
+ 'Learn more here:',
911
+ 'Starting the development server',
912
+ 'You can now view',
913
+ 'Local:',
914
+ 'On Your Network:',
915
+ 'Note that the development build',
916
+ 'To create a production build',
917
+ 'webpack compiled successfully'
918
+ ];
919
+
920
+ // On filtre les lignes pour ne garder que le vrai code/debug
921
+ const filteredOutput = lines.filter(line => {
922
+ return !forbiddenTerms.some(term => line.includes(term));
923
+ }).join('\n');
924
+
925
+ // S'il reste quelque chose d'utile (un console.log du dev, un warning, une vraie erreur), on l'affiche
926
+ if (filteredOutput.trim() !== '') {
927
+ process.stdout.write(filteredOutput + '\n');
928
+ }
929
+
930
+ // 🚀 DÉTECTION DU DÉMARRAGE ET LANCEMENT DE L'UPLINK
850
931
  if (!connectionStarted && (output.includes('Local:') || output.includes('Compiled successfully'))) {
851
932
  connectionStarted = true;
852
933
 
853
- console.log('\n[Fleetbo] ---------------------------------------------------');
854
- console.log(`[Fleetbo] 🔗 Establishing Secure Uplink...`);
855
- console.log(`[Fleetbo] ⏳ Please wait for the green message...`);
856
- console.log('[Fleetbo] ---------------------------------------------------');
934
+ console.log('\x1b[33mFleetbo OS ❯\x1b[0m ---------------------------------------------------');
935
+ console.log(`\x1b[33mFleetbo OS ❯\x1b[0m 🔗 Establishing Secure Uplink...`);
936
+ console.log(`\x1b[33mFleetbo OS ❯\x1b[0m ⏳ Please wait for the green message...`);
937
+ console.log('\x1b[33mFleetbo OS ❯\x1b[0m ---------------------------------------------------');
857
938
 
858
939
  // ============================================
859
940
  // UPLINK avec auto-retry (Fleetbo OS Resilience)
@@ -885,11 +966,13 @@ else {
885
966
  const match = text.match(/https:\/\/[a-zA-Z0-9-]+\.trycloudflare\.com/);
886
967
  if (match) {
887
968
  uplinkFound = true;
888
- syncFirebase(process.env.REACT_KEY_APP, match[0], process.env.REACT_APP_TESTER_EMAIL);
969
+ // Stabilisation du noyau : on attend 1.5s
970
+ setTimeout(() => {
971
+ syncFirebase(process.env.REACT_KEY_APP, match[0], process.env.REACT_APP_TESTER_EMAIL);
972
+ }, 1500);
889
973
  }
890
974
  };
891
975
 
892
- // Écoute sur les deux flux (stdout + stderr)
893
976
  uplinkProcess.stdout.on('data', handleUplinkOutput);
894
977
  uplinkProcess.stderr.on('data', handleUplinkOutput);
895
978
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbo-cockpit-cli",
3
- "version": "1.0.72",
3
+ "version": "1.0.73",
4
4
  "description": "Fleetbo CLI - Build native mobile apps with React",
5
5
  "author": "Fleetbo",
6
6
  "license": "MIT",