fleetbo-cockpit-cli 1.0.9 → 1.0.11
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 +53 -67
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -318,57 +318,72 @@ if (command === 'alex') {
|
|
|
318
318
|
// COMMAND: android / ios (PROPULSION BUILD)
|
|
319
319
|
// ============================================
|
|
320
320
|
else if (command === 'android' || command === 'ios') {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
const extension = platform === 'android' ? '.kt' : '.swift';
|
|
325
|
-
const nativePath = path.join(process.cwd(), nativeDir);
|
|
326
|
-
|
|
327
|
-
// Vérification des modules natifs
|
|
328
|
-
let hasNativeFiles = false;
|
|
329
|
-
let nativeFileCount = 0;
|
|
330
|
-
if (fs.existsSync(nativePath)) {
|
|
331
|
-
const files = fs.readdirSync(nativePath);
|
|
332
|
-
const nativeFiles = files.filter(file => file.endsWith(extension));
|
|
333
|
-
hasNativeFiles = nativeFiles.length > 0;
|
|
334
|
-
nativeFileCount = nativeFiles.length;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
if (!hasNativeFiles) {
|
|
338
|
-
console.log(`\n\x1b[31m⚠️ ENGINE INCOMPLETE:\x1b[0m No native blueprints detected for \x1b[1m${platform.toUpperCase()}\x1b[0m.`);
|
|
339
|
-
console.log(`\x1b[90mAlex must architect at least one ${extension} module before deployment.\x1b[0m`);
|
|
340
|
-
console.log(`\x1b[90mRun: npm run fleetbo alex\x1b[0m\n`);
|
|
341
|
-
process.exit(1);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
const targetUrl = platform === 'android' ? ANDROID_BUILD_URL : IOS_BUILD_URL;
|
|
345
|
-
|
|
321
|
+
|
|
322
|
+
// 🟢 DÉBUT DE LA PROTECTION (Fonction Async Immédiate)
|
|
323
|
+
// Cela garantit que le code fonctionne partout, même via 'require()'
|
|
346
324
|
(async () => {
|
|
325
|
+
|
|
326
|
+
// 🛑 INTERCEPTION IOS : BLOQUAGE NET (MAINTENANCE/BETA)
|
|
327
|
+
if (command === 'ios') {
|
|
328
|
+
console.log(`\n\x1b[36m⚡ FLEETBO IOS PROPULSION\x1b[0m`);
|
|
329
|
+
console.log(`\x1b[33m[0/3] Initializing Neural Uplink...\x1b[0m`);
|
|
330
|
+
|
|
331
|
+
// ✅ Ce 'await' est maintenant sécurisé
|
|
332
|
+
await new Promise(r => setTimeout(r, 800));
|
|
333
|
+
|
|
334
|
+
console.log(`\n\x1b[31m⛔ PROPULSION ABORTED: iOS Frequency Restricted.\x1b[0m`);
|
|
335
|
+
console.log(`\x1b[90m This module is currently reserved for Vanguard Pilots (Closed Beta).\x1b[0m`);
|
|
336
|
+
console.log(`\x1b[90m Please engage propulsion on Android frequency for now.\x1b[0m\n`);
|
|
337
|
+
|
|
338
|
+
process.exit(1);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
checkGitSecurity();
|
|
342
|
+
const platform = command;
|
|
343
|
+
const nativeDir = platform === 'android' ? 'public/native/android/' : 'public/native/ios/';
|
|
344
|
+
const extension = platform === 'android' ? '.kt' : '.swift';
|
|
345
|
+
const nativePath = path.join(process.cwd(), nativeDir);
|
|
346
|
+
|
|
347
|
+
// Vérification des modules natifs
|
|
348
|
+
let hasNativeFiles = false;
|
|
349
|
+
let nativeFileCount = 0;
|
|
350
|
+
if (fs.existsSync(nativePath)) {
|
|
351
|
+
const files = fs.readdirSync(nativePath);
|
|
352
|
+
const nativeFiles = files.filter(file => file.endsWith(extension));
|
|
353
|
+
hasNativeFiles = nativeFiles.length > 0;
|
|
354
|
+
nativeFileCount = nativeFiles.length;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (!hasNativeFiles) {
|
|
358
|
+
console.log(`\n\x1b[31m⚠️ ENGINE INCOMPLETE:\x1b[0m No native blueprints detected for \x1b[1m${platform.toUpperCase()}\x1b[0m.`);
|
|
359
|
+
console.log(`\x1b[90mAlex must architect at least one ${extension} module before deployment.\x1b[0m`);
|
|
360
|
+
console.log(`\x1b[90mRun: npm run fleetbo alex\x1b[0m\n`);
|
|
361
|
+
process.exit(1);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const targetUrl = platform === 'android' ? ANDROID_BUILD_URL : IOS_BUILD_URL;
|
|
365
|
+
|
|
347
366
|
console.log(`\n\x1b[36m⚡ FLEETBO ${platform.toUpperCase()} PROPULSION\x1b[0m`);
|
|
348
367
|
console.log(`\x1b[90m ${nativeFileCount} native module(s) detected\x1b[0m\n`);
|
|
349
368
|
|
|
350
369
|
try {
|
|
351
370
|
// ==========================================================
|
|
352
|
-
//
|
|
371
|
+
// PRE-FLIGHT CHECK QUOTAS
|
|
353
372
|
// ==========================================================
|
|
354
373
|
process.stdout.write(`\x1b[33m[0/3]\x1b[0m Checking Propulsion Quotas... `);
|
|
355
374
|
try {
|
|
356
375
|
await axios.post(targetUrl, {}, {
|
|
357
376
|
headers: {
|
|
358
377
|
'x-project-id': projectId,
|
|
359
|
-
'x-preflight': 'true'
|
|
378
|
+
'x-preflight': 'true'
|
|
360
379
|
}
|
|
361
380
|
});
|
|
362
381
|
process.stdout.write(`\x1b[32mOK\x1b[0m\n\n`);
|
|
363
382
|
} catch (preflightError) {
|
|
364
383
|
process.stdout.write(`\x1b[31mDENIED\x1b[0m\n`);
|
|
365
|
-
|
|
366
|
-
// 🟢 AJOUT CRITIQUE : On capture le message d'erreur du Cloud (JSON)
|
|
367
384
|
if (preflightError.response && preflightError.response.data && preflightError.response.data.error) {
|
|
368
|
-
// On remplace l'erreur technique Axios par le message métier clair
|
|
369
385
|
throw new Error(preflightError.response.data.error);
|
|
370
386
|
}
|
|
371
|
-
// Fait sauter le code directement au "catch" global du bas sans jamais builder
|
|
372
387
|
throw preflightError;
|
|
373
388
|
}
|
|
374
389
|
|
|
@@ -376,7 +391,6 @@ else if (command === 'android' || command === 'ios') {
|
|
|
376
391
|
console.log(`\x1b[33m[1/3]\x1b[0m Building React bundle...`);
|
|
377
392
|
execSync('npm run build', { stdio: 'inherit' });
|
|
378
393
|
|
|
379
|
-
// Déterminer le dossier de build
|
|
380
394
|
let buildDir = fs.existsSync(path.join(process.cwd(), 'dist')) ? 'dist' : 'build';
|
|
381
395
|
const buildPath = path.join(process.cwd(), buildDir);
|
|
382
396
|
|
|
@@ -384,7 +398,7 @@ else if (command === 'android' || command === 'ios') {
|
|
|
384
398
|
throw new Error(`Build directory not found: ${buildDir}`);
|
|
385
399
|
}
|
|
386
400
|
|
|
387
|
-
// Étape 2: Créer le ZIP
|
|
401
|
+
// Étape 2: Créer le ZIP
|
|
388
402
|
console.log(`\n\x1b[33m[2/3]\x1b[0m Packaging bundle + native modules...`);
|
|
389
403
|
|
|
390
404
|
const zipBuffer = await new Promise((resolve, reject) => {
|
|
@@ -398,41 +412,20 @@ else if (command === 'android' || command === 'ios') {
|
|
|
398
412
|
if (err.code !== 'ENOENT') reject(err);
|
|
399
413
|
});
|
|
400
414
|
|
|
401
|
-
// ============================================================
|
|
402
|
-
// 📦 STRUCTURE DU ZIP (Compatible Fastfile + Cloud Function)
|
|
403
|
-
// ============================================================
|
|
404
|
-
// build.zip
|
|
405
|
-
// └── build/
|
|
406
|
-
// ├── index.html ← Pour assets/ (WebView)
|
|
407
|
-
// ├── static/
|
|
408
|
-
// └── native/
|
|
409
|
-
// └── android/ ← Pour modules/ (.kt)
|
|
410
|
-
// └── CameraModule.kt
|
|
411
|
-
// ============================================================
|
|
412
|
-
|
|
413
|
-
// 1. Ajouter le bundle React (dans build/)
|
|
414
415
|
archive.directory(buildPath, 'build');
|
|
415
|
-
console.log(` \x1b[32m✓\x1b[0m React bundle included`);
|
|
416
|
-
|
|
417
|
-
// 2. Ajouter les modules natifs (dans build/native/android/ ou build/native/ios/)
|
|
418
|
-
// Le Fastfile cherche: temp/build/native/android/*.kt
|
|
419
|
-
// La Cloud Function cherche: native/android/*.kt (dans le ZIP)
|
|
420
416
|
if (fs.existsSync(nativePath)) {
|
|
421
417
|
archive.directory(nativePath, `build/native/${platform}`);
|
|
422
|
-
console.log(` \x1b[32m✓\x1b[0m Native modules included (${nativeFileCount} files)`);
|
|
423
418
|
}
|
|
424
|
-
|
|
425
419
|
archive.finalize();
|
|
426
420
|
});
|
|
427
421
|
|
|
428
422
|
const sizeMB = (zipBuffer.length / 1024 / 1024).toFixed(2);
|
|
429
423
|
console.log(` \x1b[32m✓\x1b[0m Bundle ready: ${sizeMB} MB`);
|
|
430
424
|
|
|
431
|
-
// Étape 3: Upload
|
|
425
|
+
// Étape 3: Upload
|
|
432
426
|
console.log(`\n\x1b[33m[3/3]\x1b[0m Uploading to Fleetbo OS...`);
|
|
433
427
|
await showEnergyTransfer();
|
|
434
428
|
|
|
435
|
-
// 🟢 ON UTILISE UNE VARIABLE LOCALE POUR LA RÉPONSE
|
|
436
429
|
let uploadResponse;
|
|
437
430
|
try {
|
|
438
431
|
uploadResponse = await axios.post(targetUrl, zipBuffer, {
|
|
@@ -442,40 +435,33 @@ else if (command === 'android' || command === 'ios') {
|
|
|
442
435
|
},
|
|
443
436
|
maxContentLength: Infinity,
|
|
444
437
|
maxBodyLength: Infinity,
|
|
445
|
-
timeout: 120000
|
|
438
|
+
timeout: 120000
|
|
446
439
|
});
|
|
447
440
|
} catch (axiosError) {
|
|
448
|
-
// 🛑 SI AXIOS PLANTE (400, 403, 500), ON LANCE UNE ERREUR CLAIRE POUR LE CATCH GLOBAL
|
|
449
|
-
// axiosError.response.data contient le JSON renvoyé par FandroidBuild
|
|
450
441
|
if (axiosError.response && axiosError.response.data && axiosError.response.data.error) {
|
|
451
442
|
throw new Error(axiosError.response.data.error);
|
|
452
443
|
} else {
|
|
453
|
-
// Timeout ou erreur réseau pure
|
|
454
444
|
throw new Error(`Connection to OS failed: ${axiosError.message}`);
|
|
455
445
|
}
|
|
456
446
|
}
|
|
457
447
|
|
|
458
|
-
// 🟢 SI AXIOS RÉUSSIT MAIS QUE LA RÉPONSE N'EST PAS UN SUCCÈS LOGIQUE
|
|
459
448
|
if (uploadResponse.data && uploadResponse.data.success) {
|
|
460
449
|
console.log(`\n\x1b[32m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
|
|
461
450
|
console.log(`\x1b[32m✓ ${platform.toUpperCase()} PROPULSION SUCCESSFUL\x1b[0m`);
|
|
462
451
|
console.log(`\x1b[32m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
|
|
463
452
|
console.log(`\x1b[90m Deployment ID: ${uploadResponse.data.deploymentId || 'N/A'}\x1b[0m`);
|
|
464
|
-
console.log(`\x1b[90m
|
|
453
|
+
console.log(`\x1b[90m ${uploadResponse.data.message || 'Complete.'}\x1b[0m\n`);
|
|
465
454
|
} else {
|
|
466
|
-
// Ce cas ne devrait pas arriver si le backend est bien codé (il renverrait une erreur HTTP), mais au cas où :
|
|
467
455
|
throw new Error(uploadResponse.data?.error || 'Unknown logical error from Factory');
|
|
468
456
|
}
|
|
469
457
|
|
|
470
|
-
} catch (error) {
|
|
458
|
+
} catch (error) {
|
|
471
459
|
console.log(`\n\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
|
|
472
460
|
console.log(`\x1b[31m✗ PROPULSION FAILED\x1b[0m`);
|
|
473
461
|
console.log(`\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
|
|
474
462
|
|
|
475
|
-
// L'erreur est maintenant propre, on l'affiche directement
|
|
476
463
|
console.error(`\x1b[31m Error:\x1b[0m ${error.message}`);
|
|
477
464
|
|
|
478
|
-
// Messages d'aide selon l'erreur
|
|
479
465
|
if (error.message.includes('Limit') || error.message.includes('Quota')) {
|
|
480
466
|
console.log(`\n\x1b[33m 💡 Tip:\x1b[0m Upgrade to Senior Pilot for more builds.`);
|
|
481
467
|
} else if (error.message.includes('No native module')) {
|
|
@@ -483,11 +469,11 @@ else if (command === 'android' || command === 'ios') {
|
|
|
483
469
|
} else if (error.message.includes('Trial Period Ended')) {
|
|
484
470
|
console.log(`\n\x1b[33m 💡 Tip:\x1b[0m Your free sprint is over. Upgrade to Senior Pilot on fleetbo.io.`);
|
|
485
471
|
}
|
|
486
|
-
|
|
487
472
|
console.log('');
|
|
488
473
|
process.exit(1);
|
|
489
474
|
}
|
|
490
|
-
|
|
475
|
+
|
|
476
|
+
})(); // 🟢 FIN DE LA PROTECTION
|
|
491
477
|
}
|
|
492
478
|
// ============================================
|
|
493
479
|
// COMMAND: page / g / generate
|