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.
- package/install-react-template.js +7 -74
- 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
|
-
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\${
|
|
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();
|