fleetbo-cockpit-cli 1.0.70 → 1.0.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.js +52 -131
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -146,10 +146,9 @@ const showEnergyTransfer = async () => {
|
|
|
146
146
|
|
|
147
147
|
// Détecte TOUS les mots en PascalCase (ex: GuestCreator, CameraModule, Tab2)
|
|
148
148
|
const extractPotentialModules = (text) => {
|
|
149
|
-
|
|
150
|
-
const regex = /\b[A-Z][a-z]+[A-Z][a-zA-Z0-9_]*\b/g;
|
|
149
|
+
const regex = /\b[A-Z][a-zA-Z0-9_]{2,}\b/g;
|
|
151
150
|
const matches = text.match(regex) || [];
|
|
152
|
-
return [...new Set(matches)];
|
|
151
|
+
return [...new Set(matches)]; // Dédoublonne les résultats
|
|
153
152
|
};
|
|
154
153
|
|
|
155
154
|
|
|
@@ -220,8 +219,8 @@ if (command === 'alex') {
|
|
|
220
219
|
return;
|
|
221
220
|
}
|
|
222
221
|
|
|
223
|
-
// 📋 INTERCEPTION:
|
|
224
|
-
const isListingRequest = /^(liste|list|quels modules|montre les modules
|
|
222
|
+
// 📋 INTERCEPTION : LISTER LES MODULES
|
|
223
|
+
const isListingRequest = /^(liste|list|quels modules|montre les modules)/i.test(prompt);
|
|
225
224
|
if (isListingRequest) {
|
|
226
225
|
process.stdout.write(` \x1b[90m🔍 Scanning OS Cache...\x1b[0m\n`);
|
|
227
226
|
const cacheRes = await getModuleCache({ projectId, moduleName: null });
|
|
@@ -233,7 +232,7 @@ if (command === 'alex') {
|
|
|
233
232
|
console.log(` ${metalColor}■\x1b[0m \x1b[1m${m.moduleName}\x1b[0m \x1b[90m(${m.platform})\x1b[0m`);
|
|
234
233
|
});
|
|
235
234
|
} else {
|
|
236
|
-
console.log(`\n \x1b[
|
|
235
|
+
console.log(`\n \x1b[90mAucun module trouvé dans l'infrastructure de ce projet.\x1b[0m`);
|
|
237
236
|
}
|
|
238
237
|
return;
|
|
239
238
|
}
|
|
@@ -241,67 +240,33 @@ if (command === 'alex') {
|
|
|
241
240
|
console.log('\x1b[33m🧠 Alex is thinking...\x1b[0m');
|
|
242
241
|
|
|
243
242
|
try {
|
|
244
|
-
// ---
|
|
243
|
+
// --- SYSTÈME DE MÉMOIRE (SMART CACHE SCANNER) ---
|
|
245
244
|
let contextInjection = "";
|
|
246
245
|
const potentialModules = extractPotentialModules(prompt);
|
|
247
|
-
|
|
248
|
-
let targetModuleContext = "";
|
|
249
|
-
let referenceContexts = "";
|
|
250
246
|
|
|
251
|
-
for (
|
|
252
|
-
|
|
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`);
|
|
247
|
+
for (const modName of potentialModules) {
|
|
248
|
+
process.stdout.write(` \x1b[90m🔍 Checking os cache for ${modName}...\x1b[0m`);
|
|
264
249
|
const cache = await getModuleCache({ projectId, moduleName: modName });
|
|
265
250
|
|
|
266
251
|
if (cache.found) {
|
|
267
252
|
process.stdout.write(` \x1b[32mFOUND METAL\x1b[0m\n`);
|
|
268
253
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
// LE MOCK EST BANI ! Le Métal est la seule source de vérité.
|
|
279
|
-
const intent = getContextIntent(prompt);
|
|
280
|
-
if (intent === "MODIFICATION") {
|
|
281
|
-
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`;
|
|
282
|
-
} else {
|
|
283
|
-
targetModuleContext = `\n--- CONTEXTE : BASE DE TRAVAIL (${modName}) ---\n${memoryScript}\n`;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
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`;
|
|
260
|
+
|
|
261
|
+
prompt = contextInjection + "\n\n[INSTRUCTION DU PILOTE]\n" + prompt;
|
|
262
|
+
break;
|
|
286
263
|
} else {
|
|
287
264
|
process.stdout.write(` \x1b[31mNOT FOUND\x1b[0m\n`);
|
|
288
265
|
}
|
|
289
266
|
}
|
|
267
|
+
// --- FIN MODIFICATION MÉMOIRE ---
|
|
290
268
|
|
|
291
|
-
|
|
292
|
-
if (contextInjection) {
|
|
293
|
-
prompt = contextInjection + "\n\n[INSTRUCTION DU PILOTE]\n" + prompt;
|
|
294
|
-
}
|
|
295
|
-
// --- END MEMORY MODIFICATION ---
|
|
296
|
-
|
|
297
|
-
// 🟢 NEW: Real-time timestamp injection
|
|
298
|
-
const now = new Date();
|
|
299
|
-
// Clean format: YYYY-MM-DD at HH:MM:SS
|
|
300
|
-
const exactTime = now.toISOString().split('T')[0] + ' at ' + now.toTimeString().split(' ')[0];
|
|
301
|
-
|
|
302
|
-
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.]`;
|
|
303
|
-
|
|
304
|
-
const result = await axios.post(ALEX_ENGINE_URL, { prompt: promptWithTime, projectType: 'android' }, {
|
|
269
|
+
const result = await axios.post(ALEX_ENGINE_URL, { prompt, projectType: 'android' }, {
|
|
305
270
|
headers: { 'x-project-id': projectId }
|
|
306
271
|
});
|
|
307
272
|
|
|
@@ -311,12 +276,6 @@ if (command === 'alex') {
|
|
|
311
276
|
try { aiData = JSON.parse(aiData); } catch (_) {}
|
|
312
277
|
}
|
|
313
278
|
|
|
314
|
-
// 🟢 DISPLAY REASONING IN TERMINAL
|
|
315
|
-
if (aiData.thinking_process) {
|
|
316
|
-
// Show start of reasoning in gray for info
|
|
317
|
-
console.log(` \x1b[90m🧠 Alex Analysis: ${aiData.thinking_process.substring(0, 150)}...\x1b[0m`);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
279
|
process.stdout.write('\x1b[A\r' + ' '.repeat(50) + '\r');
|
|
321
280
|
|
|
322
281
|
if (aiData.status === 'quota_exceeded') {
|
|
@@ -353,21 +312,21 @@ if (command === 'alex') {
|
|
|
353
312
|
const formattedMsg = wrapText(rawMsg, 85);
|
|
354
313
|
console.log('\x1b[32mAlex ❯\x1b[0m ' + formattedMsg);
|
|
355
314
|
|
|
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
|
+
}
|
|
356
323
|
}
|
|
357
324
|
|
|
358
|
-
// ---
|
|
325
|
+
// --- C'EST ICI QUE LES FICHIERS SONT CRÉÉS ---
|
|
359
326
|
if (aiData.status === 'success' && aiData.moduleData) {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
// 🛡️ ANTI-DUMP SHIELD (Prevents terminal flooding)
|
|
363
|
-
if (moduleName) {
|
|
364
|
-
// Cleanup module name
|
|
365
|
-
moduleName = moduleName.split('\n')[0].replace(/["'{}]/g, '').trim();
|
|
366
|
-
if (moduleName.length > 40) moduleName = moduleName.substring(0, 40) + "...";
|
|
367
|
-
}
|
|
368
|
-
|
|
327
|
+
const { fileName, code, mockFileName, mockCode, moduleName, instructions, config_offload } = aiData.moduleData;
|
|
369
328
|
console.log(` \x1b[90m Architecting: ${moduleName}\x1b[0m`);
|
|
370
|
-
|
|
329
|
+
|
|
371
330
|
const writeFile = (dir, name, content) => {
|
|
372
331
|
const fullPath = path.join(process.cwd(), dir);
|
|
373
332
|
const filePath = path.join(fullPath, name);
|
|
@@ -401,7 +360,7 @@ if (command === 'alex') {
|
|
|
401
360
|
}
|
|
402
361
|
}
|
|
403
362
|
|
|
404
|
-
// --- KERNEL
|
|
363
|
+
// --- SYNCHRONISATION DU KERNEL ---
|
|
405
364
|
const depsCount = config_offload?.dependencies?.length || 0;
|
|
406
365
|
process.stdout.write(` \x1b[33m[Cloud Inject]\x1b[0m Archiving ${moduleName} to OS (${depsCount} libs)...`);
|
|
407
366
|
|
|
@@ -415,8 +374,7 @@ if (command === 'alex') {
|
|
|
415
374
|
code: code,
|
|
416
375
|
mockFileName: mockFileName,
|
|
417
376
|
mockCode: mockCode,
|
|
418
|
-
config_offload: config_offload || { dependencies: [], permissions: [] }
|
|
419
|
-
dataSchema: dataSchema || null // 👈 LA LIGNE MAGIQUE
|
|
377
|
+
config_offload: config_offload || { dependencies: [], permissions: [] }
|
|
420
378
|
}
|
|
421
379
|
});
|
|
422
380
|
process.stdout.write(` \x1b[32mOK\x1b[0m\n`);
|
|
@@ -424,18 +382,9 @@ if (command === 'alex') {
|
|
|
424
382
|
process.stdout.write(` \x1b[31mFAILED\x1b[0m\n`);
|
|
425
383
|
console.error(` ⚠️ OS sync failed: ${err.message}`);
|
|
426
384
|
}
|
|
427
|
-
// 🟢 LE FUEL EST DÉPLACÉ ICI (TOUTE FIN DU TRY)
|
|
428
|
-
if (aiData.remainingConsultations !== undefined) {
|
|
429
|
-
const remaining = aiData.remainingConsultations;
|
|
430
|
-
const limit = aiData.consultationLimit || 7;
|
|
431
|
-
const tierLabel = aiData.tier.toUpperCase();
|
|
432
|
-
const percent = Math.round((remaining / limit) * 100);
|
|
433
|
-
const energyColor = percent > 20 ? '\x1b[32m' : '\x1b[31m';
|
|
434
|
-
console.log(`\n\x1b[36m⚡ Architect Fuel:\x1b[0m ${energyColor}${percent}%\x1b[0m (${remaining}/${limit} instructions left) [${tierLabel}]\n`);
|
|
435
|
-
}
|
|
436
385
|
} else if (aiData.status === 'success' && !aiData.moduleData) {
|
|
437
|
-
//
|
|
438
|
-
console.log(`\n\x1b[31m⚠️
|
|
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`);
|
|
439
388
|
}
|
|
440
389
|
} catch (error) {
|
|
441
390
|
process.stdout.write('\r' + ' '.repeat(50) + '\r');
|
|
@@ -477,25 +426,25 @@ if (command === 'alex') {
|
|
|
477
426
|
|
|
478
427
|
process.stdout.write(' '.repeat(60) + '\r');
|
|
479
428
|
|
|
480
|
-
// 1.
|
|
429
|
+
// 1. IDENTITÉ
|
|
481
430
|
console.log('\n\x1b[32m🤖 Alex is online.\x1b[0m');
|
|
482
431
|
console.log('\x1b[90m Your JS stays the brain. I forge the native muscle.\x1b[0m');
|
|
483
432
|
|
|
484
|
-
// 2. FORGE
|
|
433
|
+
// 2. CE QUE JE FORGE
|
|
485
434
|
console.log('\n\x1b[36m⚡ WHAT I CAN FORGE:\x1b[0m');
|
|
486
435
|
console.log('');
|
|
487
436
|
console.log(' \x1b[1m📷 Hardware\x1b[0m\x1b[90m Camera, Scanner, GPS, Biometrics, Sensors\x1b[0m');
|
|
488
437
|
console.log(' \x1b[1m🎬 High-Perf\x1b[0m\x1b[90m Infinite Feeds, Video Players, Swipe Decks\x1b[0m');
|
|
489
438
|
console.log(' \x1b[1m🏗️ Sovereign\x1b[0m\x1b[90m Full screens: form + photo + save-to-cloud\x1b[0m');
|
|
490
439
|
|
|
491
|
-
// 3. COLLABORATION
|
|
440
|
+
// 3. LA COLLABORATION
|
|
492
441
|
console.log('\n\x1b[36m💡 TELL ME "WHAT + WHY":\x1b[0m');
|
|
493
442
|
console.log('\x1b[90m I will analyze your need and recommend the perfect module to forge.\x1b[0m');
|
|
494
443
|
console.log('');
|
|
495
444
|
console.log(' \x1b[33m"I need a camera [WHAT] to scan receipts for my expense tracker [WHY]"\x1b[0m');
|
|
496
445
|
console.log(' \x1b[33m"I need a form [WHAT] to add products with photos to my catalog [WHY]"\x1b[0m');
|
|
497
446
|
|
|
498
|
-
// 4.
|
|
447
|
+
// 4. LA PRISE DE COMMANDE
|
|
499
448
|
console.log('\n\x1b[32mAlex ❯\x1b[0m I am ready. Describe your feature, and I will architect the solution.');
|
|
500
449
|
console.log('');
|
|
501
450
|
|
|
@@ -532,7 +481,7 @@ if (command === 'alex') {
|
|
|
532
481
|
inputBuffer = "";
|
|
533
482
|
|
|
534
483
|
if (finalPrompt.length > 1000) {
|
|
535
|
-
console.log(`\n\x1b[31m⛔ [Alex Safety] Mission
|
|
484
|
+
console.log(`\n\x1b[31m⛔ [Alex Safety] Mission rejetée : Taille excessive (${finalPrompt.length}/1000 caractères).\x1b[0m`);
|
|
536
485
|
rl.setPrompt(`\x1b[34m${dynamicUsername} ❯ \x1b[0m`);
|
|
537
486
|
rl.prompt();
|
|
538
487
|
return;
|
|
@@ -847,13 +796,13 @@ else {
|
|
|
847
796
|
try {
|
|
848
797
|
await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl, tester: testerEmail });
|
|
849
798
|
console.log('\n\x1b[32mEngine started successfully\x1b[0m');
|
|
850
|
-
console.log(`\x1b[
|
|
851
|
-
console.log('\x1b[
|
|
852
|
-
console.log('\x1b[
|
|
853
|
-
console.log(`\x1b[
|
|
854
|
-
console.log(`\x1b[34mPilot Instruction ❯\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`);
|
|
855
804
|
} catch (err) {
|
|
856
|
-
console.error(
|
|
805
|
+
console.error(`[Fleetbo] Sync Error: ${err.message}`);
|
|
857
806
|
}
|
|
858
807
|
}
|
|
859
808
|
|
|
@@ -890,7 +839,7 @@ else {
|
|
|
890
839
|
}
|
|
891
840
|
});
|
|
892
841
|
|
|
893
|
-
|
|
842
|
+
devServer.stdout.pipe(process.stdout);
|
|
894
843
|
devServer.stderr.pipe(process.stderr);
|
|
895
844
|
|
|
896
845
|
let connectionStarted = false;
|
|
@@ -898,39 +847,13 @@ else {
|
|
|
898
847
|
devServer.stdout.on('data', (data) => {
|
|
899
848
|
const output = data.toString();
|
|
900
849
|
|
|
901
|
-
// 🛡️ FILTRE ANTI-PLOMBERIE FLEETBO
|
|
902
|
-
const lines = output.split('\n');
|
|
903
|
-
const forbiddenTerms = [
|
|
904
|
-
'Attempting to bind to HOST',
|
|
905
|
-
'If this was unintentional',
|
|
906
|
-
'Learn more here:',
|
|
907
|
-
'Starting the development server',
|
|
908
|
-
'You can now view',
|
|
909
|
-
'Local:',
|
|
910
|
-
'On Your Network:',
|
|
911
|
-
'Note that the development build',
|
|
912
|
-
'To create a production build',
|
|
913
|
-
'webpack compiled successfully'
|
|
914
|
-
];
|
|
915
|
-
|
|
916
|
-
// On filtre les lignes pour ne garder que le vrai code/debug
|
|
917
|
-
const filteredOutput = lines.filter(line => {
|
|
918
|
-
return !forbiddenTerms.some(term => line.includes(term));
|
|
919
|
-
}).join('\n');
|
|
920
|
-
|
|
921
|
-
// S'il reste quelque chose d'utile (un console.log du dev, un warning, une vraie erreur), on l'affiche
|
|
922
|
-
if (filteredOutput.trim() !== '') {
|
|
923
|
-
process.stdout.write(filteredOutput + '\n');
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
// 🚀 DÉTECTION DU DÉMARRAGE ET LANCEMENT DE L'UPLINK
|
|
927
850
|
if (!connectionStarted && (output.includes('Local:') || output.includes('Compiled successfully'))) {
|
|
928
851
|
connectionStarted = true;
|
|
929
852
|
|
|
930
|
-
console.log('\
|
|
931
|
-
console.log(
|
|
932
|
-
console.log(
|
|
933
|
-
console.log('
|
|
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
857
|
|
|
935
858
|
// ============================================
|
|
936
859
|
// UPLINK avec auto-retry (Fleetbo OS Resilience)
|
|
@@ -962,13 +885,11 @@ else {
|
|
|
962
885
|
const match = text.match(/https:\/\/[a-zA-Z0-9-]+\.trycloudflare\.com/);
|
|
963
886
|
if (match) {
|
|
964
887
|
uplinkFound = true;
|
|
965
|
-
|
|
966
|
-
setTimeout(() => {
|
|
967
|
-
syncFirebase(process.env.REACT_KEY_APP, match[0], process.env.REACT_APP_TESTER_EMAIL);
|
|
968
|
-
}, 1500);
|
|
888
|
+
syncFirebase(process.env.REACT_KEY_APP, match[0], process.env.REACT_APP_TESTER_EMAIL);
|
|
969
889
|
}
|
|
970
890
|
};
|
|
971
891
|
|
|
892
|
+
// Écoute sur les deux flux (stdout + stderr)
|
|
972
893
|
uplinkProcess.stdout.on('data', handleUplinkOutput);
|
|
973
894
|
uplinkProcess.stderr.on('data', handleUplinkOutput);
|
|
974
895
|
|