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.
- package/install-react-template.js +5 -73
- package/package.json +1 -1
|
@@ -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\${
|
|
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();
|