create-fleetbo-project 1.2.45 → 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
- prompt: "ping", validateProject: true, checkNetwork: true
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,27 +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" ');
163
+ console.error(\`\\x1b[90m(Ensure you are running the runtime for project: \${keyApp})\\x1b[0m\`);
195
164
  process.exit(1);
196
165
  }
197
-
198
166
  process.stdout.write(' '.repeat(60) + '\\r');
199
-
200
167
  console.log('\\n\\x1b[32m🤖 Alex is now online.\\x1b[0m');
201
168
  console.log('\\x1b[32mAlex ❯\\x1b[0m Welcome! I am Alex, your architect. What are we building today?');
202
169
  console.log('');
203
-
204
- const userName = testerEmail ? testerEmail.split('@')[0] : 'Dev';
205
170
  const rl = readline.createInterface({
206
171
  input: process.stdin,
207
172
  output: process.stdout,
208
- prompt: \`\\x1b[34m\${userName} ❯ \\x1b[0m\`
173
+ prompt: \`\\x1b[34m\${dynamicUsername} ❯ \\x1b[0m\`
209
174
  });
210
-
211
175
  rl.prompt();
212
-
213
176
  rl.on('line', async (line) => {
214
177
  if (['exit', 'quit'].includes(line.trim().toLowerCase())) {
215
178
  console.log('\\n\\x1b[90m👋 Alex session closed.\\x1b[0m');
@@ -230,7 +193,6 @@ if (command === 'alex') {
230
193
  else processAlexRequest(initialPrompt);
231
194
  return;
232
195
  }
233
-
234
196
  if (command === 'deploy') {
235
197
  checkGitSecurity();
236
198
  (async () => {
@@ -253,15 +215,12 @@ if (command === 'deploy') {
253
215
  })();
254
216
  return;
255
217
  }
256
-
257
218
  const GENERATOR_COMMANDS = ['page', 'g', 'generate', 'android', 'ios'];
258
219
  if (GENERATOR_COMMANDS.includes(command)) {
259
220
  try { require('./page.js'); } catch (e) { console.error(e.message); process.exit(1); }
260
221
  return;
261
222
  }
262
-
263
223
  const NULL_DEV = process.platform === 'win32' ? '>nul 2>&1' : '2>/dev/null';
264
-
265
224
  function killProcessOnPort(port) {
266
225
  try {
267
226
  if (process.platform !== 'win32') {
@@ -270,14 +229,12 @@ function killProcessOnPort(port) {
270
229
  }
271
230
  } catch (e) {}
272
231
  }
273
-
274
232
  function killNetworkService() {
275
233
  try {
276
234
  const cmd = process.platform === 'win32' ? 'taskkill /IM cloudflared.exe /F' : 'pkill cloudflared';
277
235
  execSync(cmd + ' ' + NULL_DEV);
278
236
  } catch (e) {}
279
237
  }
280
-
281
238
  let isExiting = false;
282
239
  async function cleanupAndExit(code = 0) {
283
240
  if (isExiting) return;
@@ -292,7 +249,6 @@ async function cleanupAndExit(code = 0) {
292
249
  }
293
250
  process.on('SIGINT', () => cleanupAndExit(0));
294
251
  process.on('SIGTERM', () => cleanupAndExit(0));
295
-
296
252
  async function syncFirebase(keyApp, networkUrl, testerEmail) {
297
253
  try {
298
254
  await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl, tester: testerEmail });
@@ -306,7 +262,6 @@ async function syncFirebase(keyApp, networkUrl, testerEmail) {
306
262
  console.error(\`[Fleetbo] ❌ Sync Error: \${err.message}\`);
307
263
  }
308
264
  }
309
-
310
265
  async function runDevEnvironment() {
311
266
  console.log(\`[Fleetbo] 🛡️ Initializing Dev Environment...\`);
312
267
  killNetworkService();
@@ -321,7 +276,6 @@ async function runDevEnvironment() {
321
276
  });
322
277
  devServer.stdout.pipe(process.stdout);
323
278
  devServer.stderr.pipe(process.stderr);
324
-
325
279
  let connectionStarted = false;
326
280
  devServer.stdout.on('data', (data) => {
327
281
  const output = data.toString();
@@ -343,28 +297,18 @@ async function runDevEnvironment() {
343
297
  }
344
298
  });
345
299
  }
346
-
347
300
  runDevEnvironment();
348
301
  `;
349
-
350
- // ------------------------------------------------------------------
351
- // FIN CONTENU CLI
352
- // ------------------------------------------------------------------
353
-
354
-
355
302
  const args = process.argv.slice(2);
356
303
  const projectNameArg = args.find(arg => !arg.startsWith('--'));
357
304
  const tokenArg = args.find(arg => arg.startsWith('--token='));
358
305
  const emailArg = args.find(arg => arg.startsWith('--email='));
359
-
360
306
  const bootstrapTokenArg = tokenArg ? tokenArg.split('=')[1] : null;
361
307
  const userEmailArg = emailArg ? emailArg.split('=')[1] : null;
362
-
363
308
  if (!projectNameArg || !bootstrapTokenArg || !userEmailArg) {
364
309
  console.error('\n ❌ Usage: npx create-fleetbo-project <name> --token=<token> --email=<email>');
365
310
  process.exit(1);
366
311
  }
367
-
368
312
  const projectName = projectNameArg;
369
313
  const projectDir = path.join(process.cwd(), projectName);
370
314
 
@@ -390,7 +334,6 @@ function fetchProjectKeys(token) {
390
334
  req.end();
391
335
  });
392
336
  }
393
-
394
337
  function downloadEngine(url, dest) {
395
338
  return new Promise((resolve, reject) => {
396
339
  const uri = new URL(url);
@@ -413,7 +356,6 @@ function downloadEngine(url, dest) {
413
356
  request.on('error', (err) => reject(err));
414
357
  });
415
358
  }
416
-
417
359
  async function setupProject() {
418
360
  console.log(`\n⚡ Initializing Fleetbo Framework for "${projectName}"...`);
419
361
 
@@ -438,8 +380,6 @@ async function setupProject() {
438
380
  if (!keys.enterpriseId) throw new Error("Invalid keys.");
439
381
 
440
382
  console.log(' [4/7] ⚙️ Configuring environment & CLI...');
441
-
442
- // Correction indentation .env
443
383
  const envContent = `REACT_APP_FLEETBO_DB_KEY=${keys.fleetboDBKey}
444
384
  REACT_APP_ENTERPRISE_ID=${keys.enterpriseId}
445
385
  REACT_KEY_APP=${projectName}
@@ -448,35 +388,28 @@ async function setupProject() {
448
388
  WDS_SOCKET_PORT=0`;
449
389
 
450
390
  fs.writeFileSync(path.join(projectDir, '.env'), envContent, 'utf8');
451
-
452
- console.log(' [5/7] 🛡️ Securing environment (adding .gitignore)...');
391
+ console.log(' [5/7] 🛡️ Securing environment (adding .gitignore)...');
453
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`;
454
393
  fs.writeFileSync(path.join(projectDir, '.gitignore'), gitignoreContent, 'utf8');
455
-
456
394
  const scriptsDir = path.join(projectDir, 'scripts');
457
395
  if (!fs.existsSync(scriptsDir)) fs.mkdirSync(scriptsDir, { recursive: true });
458
396
  fs.writeFileSync(path.join(scriptsDir, 'cli.js'), CLI_SCRIPT_CONTENT, 'utf8');
459
397
  try { fs.chmodSync(path.join(scriptsDir, 'cli.js'), '755'); } catch (e) {}
460
-
461
398
  console.log(' [6/7] 📚 Installing dependencies...');
462
399
  execSync('npm install', { stdio: 'inherit' });
463
400
  execSync('npm install cloudflared dotenv axios archiver --save-dev', { stdio: 'ignore' });
464
-
465
401
  console.log(' [7/7] ✨ Finalizing setup...');
466
402
  const packageJsonPath = path.join(projectDir, 'package.json');
467
403
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
468
404
  packageJson.name = projectName;
469
405
  packageJson.scripts = { ...packageJson.scripts, "fleetbo": "node scripts/cli.js", "dev": "node scripts/cli.js" };
470
406
  fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8');
471
-
472
407
  console.log('\n [Fleetbo] ✅ Project successfully created!');
473
408
  console.log(`\n👉 Run: cd ${projectName} && npm run fleetbo`);
474
-
475
409
  } catch (error) {
476
410
  console.error('\n❌ Setup failed:', error.message);
477
411
  if (fs.existsSync(projectDir)) try { fs.rmSync(projectDir, { recursive: true, force: true }); } catch(e){}
478
412
  process.exit(1);
479
413
  }
480
414
  }
481
-
482
415
  setupProject();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-fleetbo-project",
3
- "version": "1.2.45",
3
+ "version": "1.2.48",
4
4
  "description": "Creates a new Fleetbo project.",
5
5
  "main": "install-react-template.js",
6
6
  "bin": {