fleetbo-cockpit-cli 1.0.4 → 1.0.6
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 +122 -26
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -137,7 +137,7 @@ const showEnergyTransfer = async () => {
|
|
|
137
137
|
for (let i = 0; i <= width; i++) {
|
|
138
138
|
const dots = "█".repeat(i);
|
|
139
139
|
const empty = "░".repeat(width - i);
|
|
140
|
-
process.stdout.write(`\r \x1b[32m⚡
|
|
140
|
+
process.stdout.write(`\r \x1b[32m⚡ Propulsion Sync:\x1b[0m [${dots}${empty}] ${Math.round((i / width) * 100)}%`);
|
|
141
141
|
await new Promise(r => setTimeout(r, 45));
|
|
142
142
|
}
|
|
143
143
|
process.stdout.write('\n');
|
|
@@ -196,7 +196,7 @@ if (command === 'alex') {
|
|
|
196
196
|
const filePath = path.join(fullPath, name);
|
|
197
197
|
if (!fs.existsSync(fullPath)) fs.mkdirSync(fullPath, { recursive: true });
|
|
198
198
|
fs.writeFileSync(filePath, content);
|
|
199
|
-
console.log(`
|
|
199
|
+
console.log(` \x1b[32m[Written]\x1b[0m ${dir}${name}`);
|
|
200
200
|
};
|
|
201
201
|
|
|
202
202
|
if (instructions && Array.isArray(instructions) && instructions.length > 0) {
|
|
@@ -225,7 +225,7 @@ if (command === 'alex') {
|
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
if (config_offload && (config_offload.dependencies?.length > 0 || config_offload.permissions?.length > 0)) {
|
|
228
|
-
process.stdout.write(`
|
|
228
|
+
process.stdout.write(` \x1b[33m[Cloud Inject]\x1b[0m Syncing ${config_offload.dependencies?.length || 0} libs to Factory...`);
|
|
229
229
|
try {
|
|
230
230
|
await axios.post(INJECT_DEPS_URL, {
|
|
231
231
|
projectId: projectId,
|
|
@@ -237,7 +237,7 @@ if (command === 'alex') {
|
|
|
237
237
|
process.stdout.write(` \x1b[32mOK\x1b[0m\n`);
|
|
238
238
|
} catch (err) {
|
|
239
239
|
process.stdout.write(` \x1b[31mFAILED\x1b[0m\n`);
|
|
240
|
-
console.error(`
|
|
240
|
+
console.error(` ⚠️ Config sync failed: ${err.message}`);
|
|
241
241
|
}
|
|
242
242
|
}
|
|
243
243
|
}
|
|
@@ -315,57 +315,153 @@ if (command === 'alex') {
|
|
|
315
315
|
|
|
316
316
|
}
|
|
317
317
|
// ============================================
|
|
318
|
-
// COMMAND: android / ios
|
|
318
|
+
// COMMAND: android / ios (PROPULSION BUILD)
|
|
319
319
|
// ============================================
|
|
320
320
|
else if (command === 'android' || command === 'ios') {
|
|
321
321
|
checkGitSecurity();
|
|
322
322
|
const platform = command;
|
|
323
323
|
const nativeDir = platform === 'android' ? 'public/native/android/' : 'public/native/ios/';
|
|
324
324
|
const extension = platform === 'android' ? '.kt' : '.swift';
|
|
325
|
-
const
|
|
325
|
+
const nativePath = path.join(process.cwd(), nativeDir);
|
|
326
326
|
|
|
327
|
+
// Vérification des modules natifs
|
|
327
328
|
let hasNativeFiles = false;
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
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;
|
|
331
335
|
}
|
|
332
336
|
|
|
333
337
|
if (!hasNativeFiles) {
|
|
334
338
|
console.log(`\n\x1b[31m⚠️ ENGINE INCOMPLETE:\x1b[0m No native blueprints detected for \x1b[1m${platform.toUpperCase()}\x1b[0m.`);
|
|
335
|
-
console.log(`\x1b[90mAlex must architect at least one ${extension} module before deployment.\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`);
|
|
336
341
|
process.exit(1);
|
|
337
342
|
}
|
|
338
343
|
|
|
339
344
|
const targetUrl = platform === 'android' ? ANDROID_BUILD_URL : IOS_BUILD_URL;
|
|
340
345
|
|
|
341
346
|
(async () => {
|
|
342
|
-
console.log(`\n\x1b[36m⚡ FLEETBO ${platform.toUpperCase()}
|
|
347
|
+
console.log(`\n\x1b[36m⚡ FLEETBO ${platform.toUpperCase()} PROPULSION\x1b[0m`);
|
|
348
|
+
console.log(`\x1b[90m ${nativeFileCount} native module(s) detected\x1b[0m\n`);
|
|
349
|
+
|
|
343
350
|
try {
|
|
351
|
+
// ==========================================================
|
|
352
|
+
// 🟢 NOUVEAU : ÉTAPE 0 (PRE-FLIGHT CHECK QUOTAS)
|
|
353
|
+
// ==========================================================
|
|
354
|
+
process.stdout.write(`\x1b[33m[0/3]\x1b[0m Checking Propulsion Quotas... `);
|
|
355
|
+
try {
|
|
356
|
+
await axios.post(targetUrl, {}, {
|
|
357
|
+
headers: {
|
|
358
|
+
'x-project-id': projectId,
|
|
359
|
+
'x-preflight': 'true' // Signale au serveur de ne pas chercher de ZIP
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
process.stdout.write(`\x1b[32mOK\x1b[0m\n\n`);
|
|
363
|
+
} catch (preflightError) {
|
|
364
|
+
process.stdout.write(`\x1b[31mDENIED\x1b[0m\n`);
|
|
365
|
+
// Fait sauter le code directement au "catch" global du bas sans jamais builder
|
|
366
|
+
throw preflightError;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Étape 1: Build React
|
|
370
|
+
console.log(`\x1b[33m[1/3]\x1b[0m Building React bundle...`);
|
|
344
371
|
execSync('npm run build', { stdio: 'inherit' });
|
|
372
|
+
|
|
373
|
+
// Déterminer le dossier de build
|
|
345
374
|
let buildDir = fs.existsSync(path.join(process.cwd(), 'dist')) ? 'dist' : 'build';
|
|
375
|
+
const buildPath = path.join(process.cwd(), buildDir);
|
|
376
|
+
|
|
377
|
+
if (!fs.existsSync(buildPath)) {
|
|
378
|
+
throw new Error(`Build directory not found: ${buildDir}`);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Étape 2: Créer le ZIP avec le bundle ET les modules natifs
|
|
382
|
+
console.log(`\n\x1b[33m[2/3]\x1b[0m Packaging bundle + native modules...`);
|
|
346
383
|
|
|
347
384
|
const zipBuffer = await new Promise((resolve, reject) => {
|
|
348
385
|
const chunks = [];
|
|
349
386
|
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
387
|
+
|
|
350
388
|
archive.on('data', chunk => chunks.push(chunk));
|
|
351
389
|
archive.on('end', () => resolve(Buffer.concat(chunks)));
|
|
352
390
|
archive.on('error', reject);
|
|
353
|
-
archive.
|
|
391
|
+
archive.on('warning', (err) => {
|
|
392
|
+
if (err.code !== 'ENOENT') reject(err);
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
// ============================================================
|
|
396
|
+
// 📦 STRUCTURE DU ZIP (Compatible Fastfile + Cloud Function)
|
|
397
|
+
// ============================================================
|
|
398
|
+
// build.zip
|
|
399
|
+
// └── build/
|
|
400
|
+
// ├── index.html ← Pour assets/ (WebView)
|
|
401
|
+
// ├── static/
|
|
402
|
+
// └── native/
|
|
403
|
+
// └── android/ ← Pour modules/ (.kt)
|
|
404
|
+
// └── CameraModule.kt
|
|
405
|
+
// ============================================================
|
|
406
|
+
|
|
407
|
+
// 1. Ajouter le bundle React (dans build/)
|
|
408
|
+
archive.directory(buildPath, 'build');
|
|
409
|
+
console.log(` \x1b[32m✓\x1b[0m React bundle included`);
|
|
410
|
+
|
|
411
|
+
// 2. Ajouter les modules natifs (dans build/native/android/ ou build/native/ios/)
|
|
412
|
+
// Le Fastfile cherche: temp/build/native/android/*.kt
|
|
413
|
+
// La Cloud Function cherche: native/android/*.kt (dans le ZIP)
|
|
414
|
+
if (fs.existsSync(nativePath)) {
|
|
415
|
+
archive.directory(nativePath, `build/native/${platform}`);
|
|
416
|
+
console.log(` \x1b[32m✓\x1b[0m Native modules included (${nativeFileCount} files)`);
|
|
417
|
+
}
|
|
418
|
+
|
|
354
419
|
archive.finalize();
|
|
355
420
|
});
|
|
356
421
|
|
|
357
|
-
|
|
422
|
+
const sizeMB = (zipBuffer.length / 1024 / 1024).toFixed(2);
|
|
423
|
+
console.log(` \x1b[32m✓\x1b[0m Bundle ready: ${sizeMB} MB`);
|
|
424
|
+
|
|
425
|
+
// Étape 3: Upload vers Cloud Function
|
|
426
|
+
console.log(`\n\x1b[33m[3/3]\x1b[0m Uploading to Fleetbo Factory...`);
|
|
358
427
|
await showEnergyTransfer();
|
|
359
428
|
|
|
360
429
|
const res = await axios.post(targetUrl, zipBuffer, {
|
|
361
|
-
headers: {
|
|
430
|
+
headers: {
|
|
431
|
+
'Content-Type': 'application/zip',
|
|
432
|
+
'x-project-id': projectId
|
|
433
|
+
},
|
|
434
|
+
maxContentLength: Infinity,
|
|
435
|
+
maxBodyLength: Infinity,
|
|
436
|
+
timeout: 120000 // 2 minutes timeout
|
|
362
437
|
});
|
|
363
438
|
|
|
364
439
|
if (res.data.success) {
|
|
365
|
-
console.log(`\n\x1b[
|
|
440
|
+
console.log(`\n\x1b[32m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
|
|
441
|
+
console.log(`\x1b[32m✓ ${platform.toUpperCase()} PROPULSION SUCCESSFUL\x1b[0m`);
|
|
442
|
+
console.log(`\x1b[32m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
|
|
443
|
+
console.log(`\x1b[90m Build ID: ${res.data.buildId || 'N/A'}\x1b[0m`);
|
|
444
|
+
console.log(`\x1b[90m Your ${platform} bundle is now in the Factory queue.\x1b[0m\n`);
|
|
445
|
+
} else {
|
|
446
|
+
throw new Error(res.data.error || 'Unknown error from Factory');
|
|
366
447
|
}
|
|
367
|
-
|
|
368
|
-
|
|
448
|
+
|
|
449
|
+
} catch (error) {
|
|
450
|
+
console.log(`\n\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
|
|
451
|
+
console.log(`\x1b[31m✗ PROPULSION FAILED\x1b[0m`);
|
|
452
|
+
console.log(`\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m`);
|
|
453
|
+
|
|
454
|
+
const errorMsg = error.response?.data?.error || error.message;
|
|
455
|
+
console.error(`\x1b[31m Error:\x1b[0m ${errorMsg}`);
|
|
456
|
+
|
|
457
|
+
// Messages d'aide selon l'erreur
|
|
458
|
+
if (errorMsg.includes('Propulsion Limit')) {
|
|
459
|
+
console.log(`\n\x1b[33m 💡 Tip:\x1b[0m Upgrade to Senior Pilot for more builds.`);
|
|
460
|
+
} else if (errorMsg.includes('No') && errorMsg.includes('blueprint')) {
|
|
461
|
+
console.log(`\n\x1b[33m 💡 Tip:\x1b[0m Run "npm run fleetbo alex" to create native modules first.`);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
console.log('');
|
|
369
465
|
process.exit(1);
|
|
370
466
|
}
|
|
371
467
|
})();
|
|
@@ -433,10 +529,10 @@ else {
|
|
|
433
529
|
try {
|
|
434
530
|
await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl, tester: testerEmail });
|
|
435
531
|
console.log('\n\x1b[32mEngine started successfully\x1b[0m');
|
|
436
|
-
console.log(`\n\x1b[32m[Fleetbo]\x1b[
|
|
437
|
-
console.log('\x1b[32m[Fleetbo]
|
|
438
|
-
console.log('\x1b[32m[Fleetbo]
|
|
439
|
-
console.log(`\x1b[32m[Fleetbo]\x1b[
|
|
532
|
+
console.log(`\n\x1b[32m[Fleetbo]\x1b[0m -------------------------------------------------------------`);
|
|
533
|
+
console.log('\x1b[32m[Fleetbo] \x1b[1mGO GO GO ! FLEETBO COCKPIT IS READY\x1b[0m');
|
|
534
|
+
console.log('\x1b[32m[Fleetbo] You can now start coding and previewing in Studio. 🚀\x1b[0m');
|
|
535
|
+
console.log(`\x1b[32m[Fleetbo]\x1b[0m -------------------------------------------------------------`);
|
|
440
536
|
console.log(`\x1b[34mPilot Instruction ❯\x1b[0m Switch to your Fleetbo Cockpit tab to begin.\n`);
|
|
441
537
|
} catch (err) {
|
|
442
538
|
console.error(`[Fleetbo] Sync Error: ${err.message}`);
|
|
@@ -445,13 +541,13 @@ else {
|
|
|
445
541
|
|
|
446
542
|
async function runDevEnvironment() {
|
|
447
543
|
console.log(`[Fleetbo] 🛡️ Initializing Dev Environment...`);
|
|
544
|
+
|
|
545
|
+
// Mise à jour silencieuse de browserslist
|
|
448
546
|
try {
|
|
449
|
-
// Mise à jour silencieuse de la DB browserslist pour éliminer le warning "Old Data"
|
|
450
547
|
const npxExec = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
451
548
|
execSync(`${npxExec} -y update-browserslist-db@latest`, { stdio: 'ignore' });
|
|
452
|
-
} catch (e) {
|
|
453
|
-
|
|
454
|
-
}
|
|
549
|
+
} catch (e) {}
|
|
550
|
+
|
|
455
551
|
killNetworkService();
|
|
456
552
|
killProcessOnPort(PORT);
|
|
457
553
|
|
|
@@ -511,4 +607,4 @@ else {
|
|
|
511
607
|
}
|
|
512
608
|
|
|
513
609
|
runDevEnvironment();
|
|
514
|
-
}
|
|
610
|
+
}
|