create-fleetbo-project 1.2.46 → 1.2.48

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.
@@ -4,16 +4,11 @@ const { execSync } = require('child_process');
4
4
  const fs = require('fs');
5
5
  const path = require('path');
6
6
  const https = require('https');
7
-
8
7
  const repoOwner = 'FleetFleetbo';
9
8
  const repoName = 'dev.fleetbo.io';
10
9
  const branchName = 'master';
11
10
  const archiveUrl = `https://github.com/${repoOwner}/${repoName}/archive/refs/heads/${branchName}.tar.gz`;
12
11
  const bootstrapUrl = 'https://us-central1-myapp-259bf.cloudfunctions.net/bootstrapProject';
13
-
14
- // ------------------------------------------------------------------
15
- // CONTENU DU CLI (Intégré pour génération automatique)
16
- // ------------------------------------------------------------------
17
12
  const CLI_SCRIPT_CONTENT = `#!/usr/bin/env node
18
13
  const { spawn, execSync } = require('child_process');
19
14
  const fs = require('fs');
@@ -23,16 +18,13 @@ const dotenv = require('dotenv');
23
18
  const os = require('os');
24
19
  const archiver = require('archiver');
25
20
  const readline = require('readline');
26
-
27
21
  const CLOUD_ENGINE_URL = "https://us-central1-myapp-259bf.cloudfunctions.net/uploadLogicBundle";
28
22
  const UPDATE_NETWORK_URL = 'https://us-central1-myapp-259bf.cloudfunctions.net/updateDeveloperNetwork';
29
23
  const ALEX_ENGINE_URL = "https://us-central1-myapp-259bf.cloudfunctions.net/generateNativeModule";
30
24
  const APP_JS_PATH = path.join(process.cwd(), 'src/App.js');
31
25
  const PORT = 3000;
32
-
33
26
  const args = process.argv.slice(2);
34
27
  const command = args[0];
35
-
36
28
  process.env.DOTENV_SILENT = 'true';
37
29
  const envPath = path.join(process.cwd(), '.env');
38
30
  if (!fs.existsSync(envPath)) {
@@ -40,11 +32,9 @@ if (!fs.existsSync(envPath)) {
40
32
  process.exit(1);
41
33
  }
42
34
  dotenv.config({ path: envPath, quiet: true });
43
-
44
35
  const projectId = process.env.REACT_APP_ENTERPRISE_ID;
45
36
  const keyApp = process.env.REACT_KEY_APP;
46
37
  const testerEmail = process.env.REACT_APP_TESTER_EMAIL;
47
-
48
38
  const checkGitSecurity = () => {
49
39
  const gitDir = path.join(process.cwd(), '.git');
50
40
  const gitignorePath = path.join(process.cwd(), '.gitignore');
@@ -60,28 +50,21 @@ const checkGitSecurity = () => {
60
50
  }
61
51
  }
62
52
  };
63
-
64
53
  if (!projectId) {
65
54
  console.error('\\n❌ Error: Project ID missing in .env.\\n');
66
55
  process.exit(1);
67
56
  }
68
-
69
57
  const injectRouteIntoAppJs = (pageName, subPath = '') => {
70
58
  if (!fs.existsSync(APP_JS_PATH)) return false;
71
59
  let content = fs.readFileSync(APP_JS_PATH, 'utf8');
72
-
73
60
  const importAnchor = '// FLEETBO_MORE_IMPORTS';
74
61
  const alexRouteAnchor = '{/* FLEETBO_DYNAMIC ROUTES */}';
75
-
76
62
  if (!content.includes(alexRouteAnchor)) return false;
77
-
78
63
  // Chemin dynamique selon si c'est une page ou un mock
79
64
  const pathPrefix = subPath ? \`\${subPath}/\` : '';
80
65
  const importLine = \`import \${pageName} from './pages/\${pathPrefix}\${pageName}';\`;
81
-
82
66
  // CORRECTION ICI : Syntax React Router valide element={<PageName />}
83
67
  const routeLine = \`<Route path="/\${pathPrefix.toLowerCase()}\${pageName.toLowerCase()}" element={<\${pageName} />} />\`;
84
-
85
68
  let injected = false;
86
69
  if (!content.includes(importLine)) {
87
70
  content = content.replace(importAnchor, \`\${importLine}\\n\${importAnchor}\`);
@@ -92,11 +75,9 @@ const injectRouteIntoAppJs = (pageName, subPath = '') => {
92
75
  content = content.replace(alexRouteAnchor, \`\${routeLine}\\n \${alexRouteAnchor}\`);
93
76
  injected = true;
94
77
  }
95
-
96
78
  if (injected) fs.writeFileSync(APP_JS_PATH, content);
97
79
  return injected;
98
80
  };
99
-
100
81
  const showEnergyTransfer = async () => {
101
82
  const width = 30;
102
83
  for (let i = 0; i <= width; i++) {
@@ -106,30 +87,24 @@ const showEnergyTransfer = async () => {
106
87
  }
107
88
  process.stdout.write('\\n');
108
89
  };
109
-
110
90
  if (command === 'alex') {
111
91
  checkGitSecurity();
112
92
  const initialPrompt = args.slice(1).join(' ');
113
-
114
93
  const processAlexRequest = async (prompt) => {
115
94
  process.stdout.write('\\x1b[33m🧠 Alex is thinking...\\x1b[0m');
116
95
  try {
117
96
  const result = await axios.post(ALEX_ENGINE_URL, { prompt, projectType: 'android' }, {
118
97
  headers: { 'x-project-id': projectId }
119
98
  });
120
-
121
99
  const aiData = result.data;
122
100
  process.stdout.write('\\r' + ' '.repeat(50) + '\\r');
123
-
124
101
  if (aiData.status === 'quota_exceeded') {
125
102
  console.log(\`\\n\\x1b[31m⛔ ENGINE OUT OF FUEL:\\x1b[0m \${aiData.message}\`);
126
103
  return;
127
104
  }
128
-
129
105
  if (aiData.status === 'success' || aiData.status === 'message') {
130
106
  console.log('');
131
- console.log(\`\\x1b[32mAlex ❯\\x1b[0m \${aiData.message || "I'm ready."}\`);
132
-
107
+ console.log(\`\\x1b[32mAlex ❯\\x1b[0m \${aiData.message || "I'm ready."}\`);
133
108
  if (aiData.remainingTokens !== undefined) {
134
109
  const remaining = aiData.remainingTokens;
135
110
  const limit = aiData.limit || 2500;
@@ -138,11 +113,9 @@ if (command === 'alex') {
138
113
  console.log(\`\\x1b[36m📊 Energy:\\x1b[0m \${energyColor}\${percent}%\\x1b[0m (\${remaining}/\${limit} tokens left)\`);
139
114
  }
140
115
  }
141
-
142
116
  if (aiData.status === 'success' && aiData.moduleData) {
143
117
  const { fileName, code, mockFileName, mockCode, moduleName } = aiData.moduleData;
144
118
  console.log(\` \\x1b[90m⚙️ Architecting: \${moduleName}\\x1b[0m\`);
145
-
146
119
  const writeFile = (dir, name, content) => {
147
120
  const fullPath = path.join(process.cwd(), dir);
148
121
  const filePath = path.join(fullPath, name);
@@ -150,7 +123,6 @@ if (command === 'alex') {
150
123
  fs.writeFileSync(filePath, content);
151
124
  console.log(\` ✅ \\x1b[32m[Written]\\x1b[0m \${dir}\${name}\`);
152
125
  };
153
-
154
126
  if (code && fileName) {
155
127
  const folder = fileName.endsWith('.kt') ? 'public/native/android/' : 'src/pages/';
156
128
  writeFile(folder, fileName, code);
@@ -161,27 +133,24 @@ if (command === 'alex') {
161
133
  writeFile('src/pages/mocks/', 'Quick.jsx', mockCode);
162
134
  }
163
135
  }
164
-
165
136
  } catch (error) {
166
137
  process.stdout.write('\\r' + ' '.repeat(50) + '\\r');
167
138
  console.error('\\n\\x1b[31m❌ Alex Error:\\x1b[0m ' + (error.response?.data?.message || error.message));
168
139
  }
169
140
  };
170
-
171
141
  const startAlexSession = async () => {
172
142
  process.stdout.write('\\x1b[33m🛡️ Alex is checking runtime state...\\x1b[0m\\r');
173
-
174
143
  let attempts = 0;
175
144
  const maxAttempts = 5;
176
145
  let isReady = false;
177
-
146
+ let dynamicUsername = 'Pilot';
178
147
  while (attempts < maxAttempts && !isReady) {
179
148
  try {
180
149
  const validation = await axios.post(ALEX_ENGINE_URL, {
181
150
  prompt: "ping", validateProject: true, checkNetwork: true, projectKey: keyApp
182
151
  }, { headers: { 'x-project-id': projectId }, timeout: 5000 });
183
152
 
184
- if (validation.data?.isRunning) { isReady = true; break; }
153
+ if (validation.data?.isRunning) { isReady = true; dynamicUsername = validation.data.username || 'Pilot'; break; }
185
154
  attempts++;
186
155
  if (attempts < maxAttempts) await new Promise(r => setTimeout(r, 2000));
187
156
  } catch (error) {
@@ -189,28 +158,21 @@ if (command === 'alex') {
189
158
  await new Promise(r => setTimeout(r, 2000));
190
159
  }
191
160
  }
192
-
193
161
  if (!isReady) {
194
162
  console.error('\\n\\x1b[31m⚠️ ENGINE OFFLINE:\\x1b[0m Start Fleetbo runtime first: "npm run fleetbo" ');
195
163
  console.error(\`\\x1b[90m(Ensure you are running the runtime for project: \${keyApp})\\x1b[0m\`);
196
164
  process.exit(1);
197
165
  }
198
-
199
166
  process.stdout.write(' '.repeat(60) + '\\r');
200
-
201
167
  console.log('\\n\\x1b[32m🤖 Alex is now online.\\x1b[0m');
202
168
  console.log('\\x1b[32mAlex ❯\\x1b[0m Welcome! I am Alex, your architect. What are we building today?');
203
169
  console.log('');
204
-
205
- const userName = testerEmail ? testerEmail.split('@')[0] : 'Dev';
206
170
  const rl = readline.createInterface({
207
171
  input: process.stdin,
208
172
  output: process.stdout,
209
- prompt: \`\\x1b[34m\${userName} ❯ \\x1b[0m\`
173
+ prompt: \`\\x1b[34m\${dynamicUsername} ❯ \\x1b[0m\`
210
174
  });
211
-
212
175
  rl.prompt();
213
-
214
176
  rl.on('line', async (line) => {
215
177
  if (['exit', 'quit'].includes(line.trim().toLowerCase())) {
216
178
  console.log('\\n\\x1b[90m👋 Alex session closed.\\x1b[0m');
@@ -231,7 +193,6 @@ if (command === 'alex') {
231
193
  else processAlexRequest(initialPrompt);
232
194
  return;
233
195
  }
234
-
235
196
  if (command === 'deploy') {
236
197
  checkGitSecurity();
237
198
  (async () => {
@@ -254,15 +215,12 @@ if (command === 'deploy') {
254
215
  })();
255
216
  return;
256
217
  }
257
-
258
218
  const GENERATOR_COMMANDS = ['page', 'g', 'generate', 'android', 'ios'];
259
219
  if (GENERATOR_COMMANDS.includes(command)) {
260
220
  try { require('./page.js'); } catch (e) { console.error(e.message); process.exit(1); }
261
221
  return;
262
222
  }
263
-
264
223
  const NULL_DEV = process.platform === 'win32' ? '>nul 2>&1' : '2>/dev/null';
265
-
266
224
  function killProcessOnPort(port) {
267
225
  try {
268
226
  if (process.platform !== 'win32') {
@@ -271,14 +229,12 @@ function killProcessOnPort(port) {
271
229
  }
272
230
  } catch (e) {}
273
231
  }
274
-
275
232
  function killNetworkService() {
276
233
  try {
277
234
  const cmd = process.platform === 'win32' ? 'taskkill /IM cloudflared.exe /F' : 'pkill cloudflared';
278
235
  execSync(cmd + ' ' + NULL_DEV);
279
236
  } catch (e) {}
280
237
  }
281
-
282
238
  let isExiting = false;
283
239
  async function cleanupAndExit(code = 0) {
284
240
  if (isExiting) return;
@@ -293,7 +249,6 @@ async function cleanupAndExit(code = 0) {
293
249
  }
294
250
  process.on('SIGINT', () => cleanupAndExit(0));
295
251
  process.on('SIGTERM', () => cleanupAndExit(0));
296
-
297
252
  async function syncFirebase(keyApp, networkUrl, testerEmail) {
298
253
  try {
299
254
  await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl, tester: testerEmail });
@@ -307,7 +262,6 @@ async function syncFirebase(keyApp, networkUrl, testerEmail) {
307
262
  console.error(\`[Fleetbo] ❌ Sync Error: \${err.message}\`);
308
263
  }
309
264
  }
310
-
311
265
  async function runDevEnvironment() {
312
266
  console.log(\`[Fleetbo] 🛡️ Initializing Dev Environment...\`);
313
267
  killNetworkService();
@@ -322,7 +276,6 @@ async function runDevEnvironment() {
322
276
  });
323
277
  devServer.stdout.pipe(process.stdout);
324
278
  devServer.stderr.pipe(process.stderr);
325
-
326
279
  let connectionStarted = false;
327
280
  devServer.stdout.on('data', (data) => {
328
281
  const output = data.toString();
@@ -344,28 +297,18 @@ async function runDevEnvironment() {
344
297
  }
345
298
  });
346
299
  }
347
-
348
300
  runDevEnvironment();
349
301
  `;
350
-
351
- // ------------------------------------------------------------------
352
- // FIN CONTENU CLI
353
- // ------------------------------------------------------------------
354
-
355
-
356
302
  const args = process.argv.slice(2);
357
303
  const projectNameArg = args.find(arg => !arg.startsWith('--'));
358
304
  const tokenArg = args.find(arg => arg.startsWith('--token='));
359
305
  const emailArg = args.find(arg => arg.startsWith('--email='));
360
-
361
306
  const bootstrapTokenArg = tokenArg ? tokenArg.split('=')[1] : null;
362
307
  const userEmailArg = emailArg ? emailArg.split('=')[1] : null;
363
-
364
308
  if (!projectNameArg || !bootstrapTokenArg || !userEmailArg) {
365
309
  console.error('\n ❌ Usage: npx create-fleetbo-project <name> --token=<token> --email=<email>');
366
310
  process.exit(1);
367
311
  }
368
-
369
312
  const projectName = projectNameArg;
370
313
  const projectDir = path.join(process.cwd(), projectName);
371
314
 
@@ -391,7 +334,6 @@ function fetchProjectKeys(token) {
391
334
  req.end();
392
335
  });
393
336
  }
394
-
395
337
  function downloadEngine(url, dest) {
396
338
  return new Promise((resolve, reject) => {
397
339
  const uri = new URL(url);
@@ -414,7 +356,6 @@ function downloadEngine(url, dest) {
414
356
  request.on('error', (err) => reject(err));
415
357
  });
416
358
  }
417
-
418
359
  async function setupProject() {
419
360
  console.log(`\n⚡ Initializing Fleetbo Framework for "${projectName}"...`);
420
361
 
@@ -439,8 +380,6 @@ async function setupProject() {
439
380
  if (!keys.enterpriseId) throw new Error("Invalid keys.");
440
381
 
441
382
  console.log(' [4/7] ⚙️ Configuring environment & CLI...');
442
-
443
- // Correction indentation .env
444
383
  const envContent = `REACT_APP_FLEETBO_DB_KEY=${keys.fleetboDBKey}
445
384
  REACT_APP_ENTERPRISE_ID=${keys.enterpriseId}
446
385
  REACT_KEY_APP=${projectName}
@@ -449,35 +388,28 @@ async function setupProject() {
449
388
  WDS_SOCKET_PORT=0`;
450
389
 
451
390
  fs.writeFileSync(path.join(projectDir, '.env'), envContent, 'utf8');
452
-
453
- console.log(' [5/7] 🛡️ Securing environment (adding .gitignore)...');
391
+ console.log(' [5/7] 🛡️ Securing environment (adding .gitignore)...');
454
392
  const gitignoreContent = `# Fleetbo Security\n.env\n.env.local\nnode_modules/\ndist/\nbuild/\n.DS_Store\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n`;
455
393
  fs.writeFileSync(path.join(projectDir, '.gitignore'), gitignoreContent, 'utf8');
456
-
457
394
  const scriptsDir = path.join(projectDir, 'scripts');
458
395
  if (!fs.existsSync(scriptsDir)) fs.mkdirSync(scriptsDir, { recursive: true });
459
396
  fs.writeFileSync(path.join(scriptsDir, 'cli.js'), CLI_SCRIPT_CONTENT, 'utf8');
460
397
  try { fs.chmodSync(path.join(scriptsDir, 'cli.js'), '755'); } catch (e) {}
461
-
462
398
  console.log(' [6/7] 📚 Installing dependencies...');
463
399
  execSync('npm install', { stdio: 'inherit' });
464
400
  execSync('npm install cloudflared dotenv axios archiver --save-dev', { stdio: 'ignore' });
465
-
466
401
  console.log(' [7/7] ✨ Finalizing setup...');
467
402
  const packageJsonPath = path.join(projectDir, 'package.json');
468
403
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
469
404
  packageJson.name = projectName;
470
405
  packageJson.scripts = { ...packageJson.scripts, "fleetbo": "node scripts/cli.js", "dev": "node scripts/cli.js" };
471
406
  fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8');
472
-
473
407
  console.log('\n [Fleetbo] ✅ Project successfully created!');
474
408
  console.log(`\n👉 Run: cd ${projectName} && npm run fleetbo`);
475
-
476
409
  } catch (error) {
477
410
  console.error('\n❌ Setup failed:', error.message);
478
411
  if (fs.existsSync(projectDir)) try { fs.rmSync(projectDir, { recursive: true, force: true }); } catch(e){}
479
412
  process.exit(1);
480
413
  }
481
414
  }
482
-
483
415
  setupProject();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-fleetbo-project",
3
- "version": "1.2.46",
3
+ "version": "1.2.48",
4
4
  "description": "Creates a new Fleetbo project.",
5
5
  "main": "install-react-template.js",
6
6
  "bin": {