fleetbo-cockpit-cli 1.0.71 → 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 +51 -134
- 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,70 +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
|
-
|
|
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`;
|
|
273
260
|
|
|
274
|
-
|
|
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
|
-
}
|
|
261
|
+
prompt = contextInjection + "\n\n[INSTRUCTION DU PILOTE]\n" + prompt;
|
|
262
|
+
break;
|
|
289
263
|
} else {
|
|
290
264
|
process.stdout.write(` \x1b[31mNOT FOUND\x1b[0m\n`);
|
|
291
265
|
}
|
|
292
266
|
}
|
|
267
|
+
// --- FIN MODIFICATION MÉMOIRE ---
|
|
293
268
|
|
|
294
|
-
|
|
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' }, {
|
|
269
|
+
const result = await axios.post(ALEX_ENGINE_URL, { prompt, projectType: 'android' }, {
|
|
308
270
|
headers: { 'x-project-id': projectId }
|
|
309
271
|
});
|
|
310
272
|
|
|
@@ -314,12 +276,6 @@ if (command === 'alex') {
|
|
|
314
276
|
try { aiData = JSON.parse(aiData); } catch (_) {}
|
|
315
277
|
}
|
|
316
278
|
|
|
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
|
-
|
|
323
279
|
process.stdout.write('\x1b[A\r' + ' '.repeat(50) + '\r');
|
|
324
280
|
|
|
325
281
|
if (aiData.status === 'quota_exceeded') {
|
|
@@ -356,21 +312,21 @@ if (command === 'alex') {
|
|
|
356
312
|
const formattedMsg = wrapText(rawMsg, 85);
|
|
357
313
|
console.log('\x1b[32mAlex ❯\x1b[0m ' + formattedMsg);
|
|
358
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
|
+
}
|
|
359
323
|
}
|
|
360
324
|
|
|
361
|
-
// ---
|
|
325
|
+
// --- C'EST ICI QUE LES FICHIERS SONT CRÉÉS ---
|
|
362
326
|
if (aiData.status === 'success' && aiData.moduleData) {
|
|
363
|
-
|
|
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
|
-
|
|
327
|
+
const { fileName, code, mockFileName, mockCode, moduleName, instructions, config_offload } = aiData.moduleData;
|
|
372
328
|
console.log(` \x1b[90m Architecting: ${moduleName}\x1b[0m`);
|
|
373
|
-
|
|
329
|
+
|
|
374
330
|
const writeFile = (dir, name, content) => {
|
|
375
331
|
const fullPath = path.join(process.cwd(), dir);
|
|
376
332
|
const filePath = path.join(fullPath, name);
|
|
@@ -404,7 +360,7 @@ if (command === 'alex') {
|
|
|
404
360
|
}
|
|
405
361
|
}
|
|
406
362
|
|
|
407
|
-
// --- KERNEL
|
|
363
|
+
// --- SYNCHRONISATION DU KERNEL ---
|
|
408
364
|
const depsCount = config_offload?.dependencies?.length || 0;
|
|
409
365
|
process.stdout.write(` \x1b[33m[Cloud Inject]\x1b[0m Archiving ${moduleName} to OS (${depsCount} libs)...`);
|
|
410
366
|
|
|
@@ -418,9 +374,7 @@ if (command === 'alex') {
|
|
|
418
374
|
code: code,
|
|
419
375
|
mockFileName: mockFileName,
|
|
420
376
|
mockCode: mockCode,
|
|
421
|
-
config_offload: config_offload || { dependencies: [], permissions: [] }
|
|
422
|
-
dataSchema: dataSchema || null, // 👈 LA LIGNE MAGIQUE
|
|
423
|
-
uiSchema: uiSchema || null
|
|
377
|
+
config_offload: config_offload || { dependencies: [], permissions: [] }
|
|
424
378
|
}
|
|
425
379
|
});
|
|
426
380
|
process.stdout.write(` \x1b[32mOK\x1b[0m\n`);
|
|
@@ -428,18 +382,9 @@ if (command === 'alex') {
|
|
|
428
382
|
process.stdout.write(` \x1b[31mFAILED\x1b[0m\n`);
|
|
429
383
|
console.error(` ⚠️ OS sync failed: ${err.message}`);
|
|
430
384
|
}
|
|
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
|
-
}
|
|
440
385
|
} else if (aiData.status === 'success' && !aiData.moduleData) {
|
|
441
|
-
//
|
|
442
|
-
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`);
|
|
443
388
|
}
|
|
444
389
|
} catch (error) {
|
|
445
390
|
process.stdout.write('\r' + ' '.repeat(50) + '\r');
|
|
@@ -481,25 +426,25 @@ if (command === 'alex') {
|
|
|
481
426
|
|
|
482
427
|
process.stdout.write(' '.repeat(60) + '\r');
|
|
483
428
|
|
|
484
|
-
// 1.
|
|
429
|
+
// 1. IDENTITÉ
|
|
485
430
|
console.log('\n\x1b[32m🤖 Alex is online.\x1b[0m');
|
|
486
431
|
console.log('\x1b[90m Your JS stays the brain. I forge the native muscle.\x1b[0m');
|
|
487
432
|
|
|
488
|
-
// 2. FORGE
|
|
433
|
+
// 2. CE QUE JE FORGE
|
|
489
434
|
console.log('\n\x1b[36m⚡ WHAT I CAN FORGE:\x1b[0m');
|
|
490
435
|
console.log('');
|
|
491
436
|
console.log(' \x1b[1m📷 Hardware\x1b[0m\x1b[90m Camera, Scanner, GPS, Biometrics, Sensors\x1b[0m');
|
|
492
437
|
console.log(' \x1b[1m🎬 High-Perf\x1b[0m\x1b[90m Infinite Feeds, Video Players, Swipe Decks\x1b[0m');
|
|
493
438
|
console.log(' \x1b[1m🏗️ Sovereign\x1b[0m\x1b[90m Full screens: form + photo + save-to-cloud\x1b[0m');
|
|
494
439
|
|
|
495
|
-
// 3. COLLABORATION
|
|
440
|
+
// 3. LA COLLABORATION
|
|
496
441
|
console.log('\n\x1b[36m💡 TELL ME "WHAT + WHY":\x1b[0m');
|
|
497
442
|
console.log('\x1b[90m I will analyze your need and recommend the perfect module to forge.\x1b[0m');
|
|
498
443
|
console.log('');
|
|
499
444
|
console.log(' \x1b[33m"I need a camera [WHAT] to scan receipts for my expense tracker [WHY]"\x1b[0m');
|
|
500
445
|
console.log(' \x1b[33m"I need a form [WHAT] to add products with photos to my catalog [WHY]"\x1b[0m');
|
|
501
446
|
|
|
502
|
-
// 4.
|
|
447
|
+
// 4. LA PRISE DE COMMANDE
|
|
503
448
|
console.log('\n\x1b[32mAlex ❯\x1b[0m I am ready. Describe your feature, and I will architect the solution.');
|
|
504
449
|
console.log('');
|
|
505
450
|
|
|
@@ -536,7 +481,7 @@ if (command === 'alex') {
|
|
|
536
481
|
inputBuffer = "";
|
|
537
482
|
|
|
538
483
|
if (finalPrompt.length > 1000) {
|
|
539
|
-
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`);
|
|
540
485
|
rl.setPrompt(`\x1b[34m${dynamicUsername} ❯ \x1b[0m`);
|
|
541
486
|
rl.prompt();
|
|
542
487
|
return;
|
|
@@ -851,13 +796,13 @@ else {
|
|
|
851
796
|
try {
|
|
852
797
|
await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl, tester: testerEmail });
|
|
853
798
|
console.log('\n\x1b[32mEngine started successfully\x1b[0m');
|
|
854
|
-
console.log(`\x1b[
|
|
855
|
-
console.log('\x1b[
|
|
856
|
-
console.log('\x1b[
|
|
857
|
-
console.log(`\x1b[
|
|
858
|
-
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`);
|
|
859
804
|
} catch (err) {
|
|
860
|
-
console.error(
|
|
805
|
+
console.error(`[Fleetbo] Sync Error: ${err.message}`);
|
|
861
806
|
}
|
|
862
807
|
}
|
|
863
808
|
|
|
@@ -894,7 +839,7 @@ else {
|
|
|
894
839
|
}
|
|
895
840
|
});
|
|
896
841
|
|
|
897
|
-
|
|
842
|
+
devServer.stdout.pipe(process.stdout);
|
|
898
843
|
devServer.stderr.pipe(process.stderr);
|
|
899
844
|
|
|
900
845
|
let connectionStarted = false;
|
|
@@ -902,39 +847,13 @@ else {
|
|
|
902
847
|
devServer.stdout.on('data', (data) => {
|
|
903
848
|
const output = data.toString();
|
|
904
849
|
|
|
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
|
|
931
850
|
if (!connectionStarted && (output.includes('Local:') || output.includes('Compiled successfully'))) {
|
|
932
851
|
connectionStarted = true;
|
|
933
852
|
|
|
934
|
-
console.log('\
|
|
935
|
-
console.log(
|
|
936
|
-
console.log(
|
|
937
|
-
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] ---------------------------------------------------');
|
|
938
857
|
|
|
939
858
|
// ============================================
|
|
940
859
|
// UPLINK avec auto-retry (Fleetbo OS Resilience)
|
|
@@ -966,13 +885,11 @@ else {
|
|
|
966
885
|
const match = text.match(/https:\/\/[a-zA-Z0-9-]+\.trycloudflare\.com/);
|
|
967
886
|
if (match) {
|
|
968
887
|
uplinkFound = true;
|
|
969
|
-
|
|
970
|
-
setTimeout(() => {
|
|
971
|
-
syncFirebase(process.env.REACT_KEY_APP, match[0], process.env.REACT_APP_TESTER_EMAIL);
|
|
972
|
-
}, 1500);
|
|
888
|
+
syncFirebase(process.env.REACT_KEY_APP, match[0], process.env.REACT_APP_TESTER_EMAIL);
|
|
973
889
|
}
|
|
974
890
|
};
|
|
975
891
|
|
|
892
|
+
// Écoute sur les deux flux (stdout + stderr)
|
|
976
893
|
uplinkProcess.stdout.on('data', handleUplinkOutput);
|
|
977
894
|
uplinkProcess.stderr.on('data', handleUplinkOutput);
|
|
978
895
|
|