fleetbo-cockpit-cli 1.0.62 → 1.0.64
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 +97 -37
- 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
|
-
|
|
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)];
|
|
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
|
|
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[
|
|
236
|
+
console.log(`\n \x1b[90mNo modules found in the infrastructure of this project.\x1b[0m`);
|
|
236
237
|
}
|
|
237
238
|
return;
|
|
238
239
|
}
|
|
@@ -240,12 +241,12 @@ if (command === 'alex') {
|
|
|
240
241
|
console.log('\x1b[33m🧠 Alex is thinking...\x1b[0m');
|
|
241
242
|
|
|
242
243
|
try {
|
|
243
|
-
// ---
|
|
244
|
+
// --- MEMORY SYSTEM (SMART CACHE SCANNER) ---
|
|
244
245
|
let contextInjection = "";
|
|
245
246
|
const potentialModules = extractPotentialModules(prompt);
|
|
246
247
|
|
|
247
248
|
for (const modName of potentialModules) {
|
|
248
|
-
process.stdout.write(` \x1b[90m🔍 Checking
|
|
249
|
+
process.stdout.write(` \x1b[90m🔍 Checking OS cache for ${modName}...\x1b[0m`);
|
|
249
250
|
const cache = await getModuleCache({ projectId, moduleName: modName });
|
|
250
251
|
|
|
251
252
|
if (cache.found) {
|
|
@@ -253,20 +254,36 @@ if (command === 'alex') {
|
|
|
253
254
|
|
|
254
255
|
const intent = getContextIntent(prompt);
|
|
255
256
|
const contextTitle = intent === "MODIFICATION"
|
|
256
|
-
? "
|
|
257
|
-
: "
|
|
257
|
+
? "EXISTING METAL (TO MODIFY)"
|
|
258
|
+
: "REFERENCE METAL (FOR DATA PARITY)";
|
|
259
|
+
|
|
260
|
+
// 🟢 NEW: Data Schema extraction and formatting
|
|
261
|
+
let schemaInstruction = "";
|
|
262
|
+
if (cache.module.dataSchema && Array.isArray(cache.module.dataSchema)) {
|
|
263
|
+
schemaInstruction = "\n[STRICT DATA CONTRACT]\nThe reference module uses this configuration. You MUST strictly use these collections and keys:\n";
|
|
264
|
+
cache.module.dataSchema.forEach(schema => {
|
|
265
|
+
schemaInstruction += `- Collection '${schema.collection}': fields [${schema.fields.join(', ')}]\n`;
|
|
266
|
+
});
|
|
267
|
+
}
|
|
258
268
|
|
|
259
|
-
contextInjection = `\n---
|
|
269
|
+
contextInjection = `\n--- SOVEREIGN CONTEXT: ${contextTitle} (${modName}) ---\nDOGMA: The Metal is the absolute source of truth.\n${schemaInstruction}\n\n[EXISTING NATIVE CODE]\n${cache.module.code}\n--- END OF CONTEXT ---\n`;
|
|
260
270
|
|
|
261
|
-
prompt = contextInjection + "\n\n[INSTRUCTION
|
|
271
|
+
prompt = contextInjection + "\n\n[PILOT INSTRUCTION]\n" + prompt;
|
|
262
272
|
break;
|
|
263
273
|
} else {
|
|
264
274
|
process.stdout.write(` \x1b[31mNOT FOUND\x1b[0m\n`);
|
|
265
275
|
}
|
|
266
276
|
}
|
|
267
|
-
// ---
|
|
277
|
+
// --- END MEMORY MODIFICATION ---
|
|
278
|
+
|
|
279
|
+
// 🟢 NEW: Real-time timestamp injection
|
|
280
|
+
const now = new Date();
|
|
281
|
+
// Clean format: YYYY-MM-DD at HH:MM:SS
|
|
282
|
+
const exactTime = now.toISOString().split('T')[0] + ' at ' + now.toTimeString().split(' ')[0];
|
|
283
|
+
|
|
284
|
+
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.]`;
|
|
268
285
|
|
|
269
|
-
const result = await axios.post(ALEX_ENGINE_URL, { prompt, projectType: 'android' }, {
|
|
286
|
+
const result = await axios.post(ALEX_ENGINE_URL, { prompt: promptWithTime, projectType: 'android' }, {
|
|
270
287
|
headers: { 'x-project-id': projectId }
|
|
271
288
|
});
|
|
272
289
|
|
|
@@ -276,6 +293,12 @@ if (command === 'alex') {
|
|
|
276
293
|
try { aiData = JSON.parse(aiData); } catch (_) {}
|
|
277
294
|
}
|
|
278
295
|
|
|
296
|
+
// 🟢 DISPLAY REASONING IN TERMINAL
|
|
297
|
+
if (aiData.thinking_process) {
|
|
298
|
+
// Show start of reasoning in gray for info
|
|
299
|
+
console.log(` \x1b[90m🧠 Alex Analysis: ${aiData.thinking_process.substring(0, 150)}...\x1b[0m`);
|
|
300
|
+
}
|
|
301
|
+
|
|
279
302
|
process.stdout.write('\x1b[A\r' + ' '.repeat(50) + '\r');
|
|
280
303
|
|
|
281
304
|
if (aiData.status === 'quota_exceeded') {
|
|
@@ -322,16 +345,25 @@ if (command === 'alex') {
|
|
|
322
345
|
}
|
|
323
346
|
}
|
|
324
347
|
|
|
325
|
-
// ---
|
|
348
|
+
// --- FILE CREATION LOGIC ---
|
|
326
349
|
if (aiData.status === 'success' && aiData.moduleData) {
|
|
327
|
-
|
|
350
|
+
let { fileName, code, mockFileName, mockCode, moduleName, instructions, config_offload } = aiData.moduleData;
|
|
351
|
+
|
|
352
|
+
// 🛡️ ANTI-DUMP SHIELD (Prevents terminal flooding)
|
|
353
|
+
if (moduleName) {
|
|
354
|
+
// Cleanup module name
|
|
355
|
+
moduleName = moduleName.split('\n')[0].replace(/["'{}]/g, '').trim();
|
|
356
|
+
if (moduleName.length > 40) moduleName = moduleName.substring(0, 40) + "...";
|
|
357
|
+
}
|
|
358
|
+
|
|
328
359
|
console.log(` \x1b[90m Architecting: ${moduleName}\x1b[0m`);
|
|
329
|
-
|
|
360
|
+
|
|
330
361
|
const writeFile = (dir, name, content) => {
|
|
331
362
|
const fullPath = path.join(process.cwd(), dir);
|
|
332
363
|
const filePath = path.join(fullPath, name);
|
|
333
364
|
if (!fs.existsSync(fullPath)) fs.mkdirSync(fullPath, { recursive: true });
|
|
334
365
|
fs.writeFileSync(filePath, content);
|
|
366
|
+
console.log('');
|
|
335
367
|
console.log(` \x1b[32m[Written]\x1b[0m ${dir}${name}`);
|
|
336
368
|
};
|
|
337
369
|
|
|
@@ -360,7 +392,7 @@ if (command === 'alex') {
|
|
|
360
392
|
}
|
|
361
393
|
}
|
|
362
394
|
|
|
363
|
-
// ---
|
|
395
|
+
// --- KERNEL SYNCHRONIZATION ---
|
|
364
396
|
const depsCount = config_offload?.dependencies?.length || 0;
|
|
365
397
|
process.stdout.write(` \x1b[33m[Cloud Inject]\x1b[0m Archiving ${moduleName} to OS (${depsCount} libs)...`);
|
|
366
398
|
|
|
@@ -383,8 +415,8 @@ if (command === 'alex') {
|
|
|
383
415
|
console.error(` ⚠️ OS sync failed: ${err.message}`);
|
|
384
416
|
}
|
|
385
417
|
} else if (aiData.status === 'success' && !aiData.moduleData) {
|
|
386
|
-
//
|
|
387
|
-
console.log(`\n\x1b[31m⚠️
|
|
418
|
+
// SAFETY: If formatting is broken
|
|
419
|
+
console.log(`\n\x1b[31m⚠️ Error: Alex replied, but source code could not be extracted. Try the command again.\x1b[0m\n`);
|
|
388
420
|
}
|
|
389
421
|
} catch (error) {
|
|
390
422
|
process.stdout.write('\r' + ' '.repeat(50) + '\r');
|
|
@@ -426,25 +458,25 @@ if (command === 'alex') {
|
|
|
426
458
|
|
|
427
459
|
process.stdout.write(' '.repeat(60) + '\r');
|
|
428
460
|
|
|
429
|
-
// 1.
|
|
461
|
+
// 1. IDENTITY
|
|
430
462
|
console.log('\n\x1b[32m🤖 Alex is online.\x1b[0m');
|
|
431
463
|
console.log('\x1b[90m Your JS stays the brain. I forge the native muscle.\x1b[0m');
|
|
432
464
|
|
|
433
|
-
// 2.
|
|
465
|
+
// 2. FORGE CAPABILITIES
|
|
434
466
|
console.log('\n\x1b[36m⚡ WHAT I CAN FORGE:\x1b[0m');
|
|
435
467
|
console.log('');
|
|
436
468
|
console.log(' \x1b[1m📷 Hardware\x1b[0m\x1b[90m Camera, Scanner, GPS, Biometrics, Sensors\x1b[0m');
|
|
437
469
|
console.log(' \x1b[1m🎬 High-Perf\x1b[0m\x1b[90m Infinite Feeds, Video Players, Swipe Decks\x1b[0m');
|
|
438
470
|
console.log(' \x1b[1m🏗️ Sovereign\x1b[0m\x1b[90m Full screens: form + photo + save-to-cloud\x1b[0m');
|
|
439
471
|
|
|
440
|
-
// 3.
|
|
472
|
+
// 3. COLLABORATION
|
|
441
473
|
console.log('\n\x1b[36m💡 TELL ME "WHAT + WHY":\x1b[0m');
|
|
442
474
|
console.log('\x1b[90m I will analyze your need and recommend the perfect module to forge.\x1b[0m');
|
|
443
475
|
console.log('');
|
|
444
476
|
console.log(' \x1b[33m"I need a camera [WHAT] to scan receipts for my expense tracker [WHY]"\x1b[0m');
|
|
445
477
|
console.log(' \x1b[33m"I need a form [WHAT] to add products with photos to my catalog [WHY]"\x1b[0m');
|
|
446
478
|
|
|
447
|
-
// 4.
|
|
479
|
+
// 4. READINESS
|
|
448
480
|
console.log('\n\x1b[32mAlex ❯\x1b[0m I am ready. Describe your feature, and I will architect the solution.');
|
|
449
481
|
console.log('');
|
|
450
482
|
|
|
@@ -481,7 +513,7 @@ if (command === 'alex') {
|
|
|
481
513
|
inputBuffer = "";
|
|
482
514
|
|
|
483
515
|
if (finalPrompt.length > 1000) {
|
|
484
|
-
console.log(`\n\x1b[31m⛔ [Alex Safety] Mission
|
|
516
|
+
console.log(`\n\x1b[31m⛔ [Alex Safety] Mission rejected: Excessive size (${finalPrompt.length}/1000 characters).\x1b[0m`);
|
|
485
517
|
rl.setPrompt(`\x1b[34m${dynamicUsername} ❯ \x1b[0m`);
|
|
486
518
|
rl.prompt();
|
|
487
519
|
return;
|
|
@@ -796,13 +828,13 @@ else {
|
|
|
796
828
|
try {
|
|
797
829
|
await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl, tester: testerEmail });
|
|
798
830
|
console.log('\n\x1b[32mEngine started successfully\x1b[0m');
|
|
799
|
-
console.log(`\x1b[
|
|
800
|
-
console.log('\x1b[
|
|
801
|
-
console.log('\x1b[
|
|
802
|
-
console.log(`\x1b[
|
|
803
|
-
console.log(`\x1b[34mPilot Instruction ❯\x1b[0m
|
|
831
|
+
console.log(`\x1b[32mFleetbo OS ❯\x1b[0m -------------------------------------------------------------`);
|
|
832
|
+
console.log('\x1b[32mFleetbo OS ❯\x1b[0m \x1b[1mGO GO GO ! OS IS READY\x1b[0m');
|
|
833
|
+
console.log('\x1b[32mFleetbo OS ❯\x1b[0m You can now start coding and previewing. 🚀');
|
|
834
|
+
console.log(`\x1b[32mFleetbo OS ❯\x1b[0m -------------------------------------------------------------`);
|
|
835
|
+
console.log(`\x1b[34mPilot Instruction ❯\x1b[0m Return to the Workspace. The Engine is ready for your orders.\n`);
|
|
804
836
|
} catch (err) {
|
|
805
|
-
console.error(
|
|
837
|
+
console.error(`\x1b[31mFleetbo OS ❯\x1b[0m Sync Error: ${err.message}`);
|
|
806
838
|
}
|
|
807
839
|
}
|
|
808
840
|
|
|
@@ -839,7 +871,7 @@ else {
|
|
|
839
871
|
}
|
|
840
872
|
});
|
|
841
873
|
|
|
842
|
-
devServer.stdout.pipe(process.stdout);
|
|
874
|
+
//devServer.stdout.pipe(process.stdout);
|
|
843
875
|
devServer.stderr.pipe(process.stderr);
|
|
844
876
|
|
|
845
877
|
let connectionStarted = false;
|
|
@@ -847,13 +879,39 @@ else {
|
|
|
847
879
|
devServer.stdout.on('data', (data) => {
|
|
848
880
|
const output = data.toString();
|
|
849
881
|
|
|
882
|
+
// 🛡️ FILTRE ANTI-PLOMBERIE FLEETBO
|
|
883
|
+
const lines = output.split('\n');
|
|
884
|
+
const forbiddenTerms = [
|
|
885
|
+
'Attempting to bind to HOST',
|
|
886
|
+
'If this was unintentional',
|
|
887
|
+
'Learn more here:',
|
|
888
|
+
'Starting the development server',
|
|
889
|
+
'You can now view',
|
|
890
|
+
'Local:',
|
|
891
|
+
'On Your Network:',
|
|
892
|
+
'Note that the development build',
|
|
893
|
+
'To create a production build',
|
|
894
|
+
'webpack compiled successfully'
|
|
895
|
+
];
|
|
896
|
+
|
|
897
|
+
// On filtre les lignes pour ne garder que le vrai code/debug
|
|
898
|
+
const filteredOutput = lines.filter(line => {
|
|
899
|
+
return !forbiddenTerms.some(term => line.includes(term));
|
|
900
|
+
}).join('\n');
|
|
901
|
+
|
|
902
|
+
// S'il reste quelque chose d'utile (un console.log du dev, un warning, une vraie erreur), on l'affiche
|
|
903
|
+
if (filteredOutput.trim() !== '') {
|
|
904
|
+
process.stdout.write(filteredOutput + '\n');
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
// 🚀 DÉTECTION DU DÉMARRAGE ET LANCEMENT DE L'UPLINK
|
|
850
908
|
if (!connectionStarted && (output.includes('Local:') || output.includes('Compiled successfully'))) {
|
|
851
909
|
connectionStarted = true;
|
|
852
910
|
|
|
853
|
-
console.log('\
|
|
854
|
-
console.log(
|
|
855
|
-
console.log(
|
|
856
|
-
console.log('[
|
|
911
|
+
console.log('\x1b[33mFleetbo OS ❯\x1b[0m ---------------------------------------------------');
|
|
912
|
+
console.log(`\x1b[33mFleetbo OS ❯\x1b[0m 🔗 Establishing Secure Uplink...`);
|
|
913
|
+
console.log(`\x1b[33mFleetbo OS ❯\x1b[0m ⏳ Please wait for the green message...`);
|
|
914
|
+
console.log('\x1b[33mFleetbo OS ❯\x1b[0m ---------------------------------------------------');
|
|
857
915
|
|
|
858
916
|
// ============================================
|
|
859
917
|
// UPLINK avec auto-retry (Fleetbo OS Resilience)
|
|
@@ -885,11 +943,13 @@ else {
|
|
|
885
943
|
const match = text.match(/https:\/\/[a-zA-Z0-9-]+\.trycloudflare\.com/);
|
|
886
944
|
if (match) {
|
|
887
945
|
uplinkFound = true;
|
|
888
|
-
|
|
946
|
+
// ⚡ Stabilisation du noyau : on attend 1.5s
|
|
947
|
+
setTimeout(() => {
|
|
948
|
+
syncFirebase(process.env.REACT_KEY_APP, match[0], process.env.REACT_APP_TESTER_EMAIL);
|
|
949
|
+
}, 1500);
|
|
889
950
|
}
|
|
890
951
|
};
|
|
891
952
|
|
|
892
|
-
// Écoute sur les deux flux (stdout + stderr)
|
|
893
953
|
uplinkProcess.stdout.on('data', handleUplinkOutput);
|
|
894
954
|
uplinkProcess.stderr.on('data', handleUplinkOutput);
|
|
895
955
|
|