create-fleetbo-project 1.2.40 → 1.2.41
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 +194 -86
- package/package.json +1 -1
|
@@ -31,12 +31,13 @@ const PORT = 3000;
|
|
|
31
31
|
const args = process.argv.slice(2);
|
|
32
32
|
const command = args[0];
|
|
33
33
|
|
|
34
|
+
process.env.DOTENV_SILENT = 'true';
|
|
34
35
|
const envPath = path.join(process.cwd(), '.env');
|
|
35
36
|
if (!fs.existsSync(envPath)) {
|
|
36
|
-
console.error('\\\\x1b[31m%s\\\\x1b[0m', '
|
|
37
|
+
console.error('\\\\x1b[31m%s\\\\x1b[0m', '⌠Error: Configuration file (.env) not found.');
|
|
37
38
|
process.exit(1);
|
|
38
39
|
}
|
|
39
|
-
dotenv.config({ path: envPath });
|
|
40
|
+
dotenv.config({ path: envPath, quiet: true });
|
|
40
41
|
|
|
41
42
|
const projectId = process.env.REACT_APP_ENTERPRISE_ID;
|
|
42
43
|
const keyApp = process.env.REACT_KEY_APP;
|
|
@@ -47,40 +48,47 @@ const checkGitSecurity = () => {
|
|
|
47
48
|
const gitignorePath = path.join(process.cwd(), '.gitignore');
|
|
48
49
|
if (fs.existsSync(gitDir)) {
|
|
49
50
|
if (!fs.existsSync(gitignorePath)) {
|
|
50
|
-
console.error('\\\\n\\\\x1b[31m
|
|
51
|
+
console.error('\\\\n\\\\x1b[31m🚨 SECURITY ALERT:\\\\x1b[0m .git detected but no .gitignore found.');
|
|
51
52
|
process.exit(1);
|
|
52
53
|
}
|
|
53
54
|
const gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
|
|
54
55
|
if (!gitignoreContent.includes('.env')) {
|
|
55
|
-
console.error('\\\\n\\\\x1b[31m
|
|
56
|
+
console.error('\\\\n\\\\x1b[31m🚨 CRITICAL RISK:\\\\x1b[0m .env is NOT ignored by Git.');
|
|
56
57
|
process.exit(1);
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
};
|
|
60
61
|
|
|
61
62
|
if (!projectId) {
|
|
62
|
-
console.error('\\\\
|
|
63
|
+
console.error('\\\\n⌠Error: Project ID missing in .env.\\\\n');
|
|
63
64
|
process.exit(1);
|
|
64
65
|
}
|
|
65
66
|
|
|
66
|
-
const injectRouteIntoAppJs = (pageName) => {
|
|
67
|
+
const injectRouteIntoAppJs = (pageName, subPath = '') => {
|
|
67
68
|
if (!fs.existsSync(APP_JS_PATH)) return false;
|
|
68
69
|
let content = fs.readFileSync(APP_JS_PATH, 'utf8');
|
|
69
|
-
|
|
70
|
+
|
|
71
|
+
const importAnchor = '// FLEETBO_MORE_IMPORTS';
|
|
72
|
+
const alexRouteAnchor = '{/* FLEETBO_DYNAMIC ROUTES */}';
|
|
73
|
+
|
|
74
|
+
if (!content.includes(alexRouteAnchor)) return false;
|
|
70
75
|
|
|
71
|
-
|
|
72
|
-
const
|
|
76
|
+
// Chemin dynamique selon si c'est une page ou un mock
|
|
77
|
+
const pathPrefix = subPath ? \`\\\${subPath}/\` : '';
|
|
78
|
+
const importLine = \`import \\\${pageName} from './pages/\\\${pathPrefix}\\\${pageName}';\`;
|
|
79
|
+
const routeLine = \`<Route path="/\\\${pathPrefix.toLowerCase()}\\\${pageName.toLowerCase()}" element=<\\\${\\\${pageName} />} />\`;
|
|
73
80
|
|
|
74
81
|
let injected = false;
|
|
75
|
-
if (!content.includes(importLine)
|
|
76
|
-
content = content.replace(
|
|
82
|
+
if (!content.includes(importLine)) {
|
|
83
|
+
content = content.replace(importAnchor, \`\\\${importLine}\\\\n\\\${importAnchor}\`);
|
|
77
84
|
injected = true;
|
|
78
85
|
}
|
|
79
|
-
if (!content.includes(routeLine)
|
|
80
|
-
|
|
81
|
-
content = content.replace(
|
|
86
|
+
if (!content.includes(routeLine)) {
|
|
87
|
+
// Injection précise dans l'ancre Alex
|
|
88
|
+
content = content.replace(alexRouteAnchor, \`\\\${routeLine}\\\\n \\\${alexRouteAnchor}\`);
|
|
82
89
|
injected = true;
|
|
83
90
|
}
|
|
91
|
+
|
|
84
92
|
if (injected) fs.writeFileSync(APP_JS_PATH, content);
|
|
85
93
|
return injected;
|
|
86
94
|
};
|
|
@@ -88,8 +96,8 @@ const injectRouteIntoAppJs = (pageName) => {
|
|
|
88
96
|
const showEnergyTransfer = async () => {
|
|
89
97
|
const width = 30;
|
|
90
98
|
for (let i = 0; i <= width; i++) {
|
|
91
|
-
const dots = "
|
|
92
|
-
process.stdout.write(\`\\\\r \\\\x1b[32m
|
|
99
|
+
const dots = "â–ˆ".repeat(i); const empty = "â–'".repeat(width - i);
|
|
100
|
+
process.stdout.write(\`\\\\r \\\\x1b[32mâš¡ Alex Energy Sync:\\\\x1b[0m [\\\${dots}\\\${empty}] \\\${Math.round((i / width) * 100)}%\`);
|
|
93
101
|
await new Promise(r => setTimeout(r, 45));
|
|
94
102
|
}
|
|
95
103
|
process.stdout.write('\\\\n');
|
|
@@ -100,68 +108,136 @@ if (command === 'alex') {
|
|
|
100
108
|
const initialPrompt = args.slice(1).join(' ');
|
|
101
109
|
|
|
102
110
|
const processAlexRequest = async (prompt) => {
|
|
103
|
-
process.stdout.write('\\\\
|
|
111
|
+
process.stdout.write('\\\\x1b[33m🧠Alex is thinking...\\\\x1b[0m');
|
|
104
112
|
try {
|
|
105
113
|
const result = await axios.post(ALEX_ENGINE_URL, { prompt, projectType: 'android' }, {
|
|
106
114
|
headers: { 'x-project-id': projectId }
|
|
107
115
|
});
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
|
|
117
|
+
const aiData = result.data;
|
|
118
|
+
// 1. On efface "Alex is thinking..."
|
|
119
|
+
process.stdout.write('\\\\r' + ' '.repeat(50) + '\\\\r');
|
|
120
|
+
|
|
121
|
+
// --- 1. GESTION DU QUOTA (EN ROUGE) ---
|
|
122
|
+
if (aiData.status === 'quota_exceeded') {
|
|
123
|
+
console.log(\`\\\\n\\\\x1b[31mâ›" ENGINE OUT OF FUEL:\\\\x1b[0m \\\${aiData.message}\`);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// --- 2. AFFICHAGE DE LA RÉPONSE ---
|
|
128
|
+
if (aiData.status === 'success' || aiData.status === 'message') {
|
|
129
|
+
// ✅ AJOUT : Saut de ligne pour séparer de votre commande "username â¯"
|
|
130
|
+
console.log('');
|
|
131
|
+
|
|
132
|
+
// Alex répond en Vert
|
|
133
|
+
console.log(\`\\\\x1b[32mAlex â¯\\\\x1b[0m \\\${aiData.message || "I'm ready."}\`);
|
|
134
|
+
|
|
135
|
+
// Jauge d'énergie (Bleu/Vert/Rouge)
|
|
136
|
+
if (aiData.remainingTokens !== undefined) {
|
|
137
|
+
const remaining = aiData.remainingTokens;
|
|
138
|
+
const limit = aiData.limit || 2500;
|
|
139
|
+
const percent = Math.round((remaining / limit) * 100);
|
|
140
|
+
const energyColor = percent > 30 ? '\\\\x1b[32m' : '\\\\x1b[31m';
|
|
141
|
+
console.log(\`\\\\x1b[36mðŸ"Š Energy:\\\\x1b[0m \\\${energyColor}\\\${percent}%\\\\x1b[0m (\\\${remaining}/\\\${limit} tokens left)\`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
110
144
|
|
|
145
|
+
// --- 4. TRAITEMENT DES FICHIERS (SI PRÉSENTS) ---
|
|
111
146
|
if (aiData.status === 'success' && aiData.moduleData) {
|
|
112
|
-
const { fileName, code, mockFileName, mockCode } = aiData.moduleData;
|
|
147
|
+
const { fileName, code, mockFileName, mockCode, moduleName } = aiData.moduleData;
|
|
148
|
+
console.log(\` \\\\x1b[90mâš™ï¸ Architecting: \\\${moduleName}\\\\x1b[0m\`);
|
|
149
|
+
|
|
113
150
|
const writeFile = (dir, name, content) => {
|
|
114
151
|
const fullPath = path.join(process.cwd(), dir);
|
|
115
152
|
const filePath = path.join(fullPath, name);
|
|
116
153
|
if (!fs.existsSync(fullPath)) fs.mkdirSync(fullPath, { recursive: true });
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const backupPath = filePath.replace(/(\\\\.jsx|\\\\.kt|\\\\.swift)$/, '.original\\\$1');
|
|
120
|
-
fs.copyFileSync(filePath, backupPath);
|
|
121
|
-
fs.writeFileSync(filePath, content);
|
|
122
|
-
console.log(\` ✅ \\\\x1b[33m[Updated]\\\\x1b[0m \\\${dir}\\\${name} \\\\x1b[90m(Backup created)\\\\x1b[0m\`);
|
|
123
|
-
} else {
|
|
124
|
-
fs.writeFileSync(filePath, content);
|
|
125
|
-
console.log(\` ✅ \\\\x1b[32m[Created]\\\\x1b[0m \\\${dir}\\\${name}\`);
|
|
126
|
-
}
|
|
154
|
+
fs.writeFileSync(filePath, content);
|
|
155
|
+
console.log(\` ✅ \\\\x1b[32m[Written]\\\\x1b[0m \\\${dir}\\\${name}\`);
|
|
127
156
|
};
|
|
128
|
-
|
|
129
|
-
if (code && fileName
|
|
130
|
-
|
|
157
|
+
|
|
158
|
+
if (code && fileName) {
|
|
159
|
+
const folder = fileName.endsWith('.kt') ? 'public/native/android/' : 'src/pages/';
|
|
160
|
+
writeFile(folder, fileName, code);
|
|
161
|
+
if (fileName.endsWith('.jsx')) injectRouteIntoAppJs(fileName.replace('.jsx', ''));
|
|
131
162
|
}
|
|
132
163
|
if (mockCode && mockFileName) {
|
|
133
164
|
writeFile('src/pages/mocks/', mockFileName, mockCode);
|
|
134
|
-
writeFile('src/pages/mocks/', 'Quick.
|
|
135
|
-
}
|
|
136
|
-
if (code && fileName && fileName.endsWith('.jsx') && !mockCode) {
|
|
137
|
-
const pageName = fileName.replace('.jsx', '');
|
|
138
|
-
writeFile('src/pages/', fileName, code);
|
|
139
|
-
injectRouteIntoAppJs(pageName);
|
|
165
|
+
writeFile('src/pages/mocks/', 'Quick.jsx', mockCode);
|
|
140
166
|
}
|
|
141
|
-
console.log('\\\\n\\\\x1b[32mAlex ❯\\\\x1b[0m ' + aiData.message);
|
|
142
167
|
}
|
|
143
|
-
|
|
168
|
+
|
|
169
|
+
} catch (error) {
|
|
170
|
+
process.stdout.write('\\\\r' + ' '.repeat(50) + '\\\\r');
|
|
171
|
+
console.error('\\\\n\\\\x1b[31m⌠Alex Error:\\\\x1b[0m ' + (error.response?.data?.message || error.message));
|
|
172
|
+
}
|
|
144
173
|
};
|
|
145
174
|
|
|
146
175
|
const startAlexSession = async () => {
|
|
147
|
-
process.stdout.write('\\\\
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
176
|
+
process.stdout.write('\\\\x1b[33mðŸ›¡ï¸ Alex is checking runtime state...\\\\x1b[0m\\\\r');
|
|
177
|
+
|
|
178
|
+
let attempts = 0;
|
|
179
|
+
const maxAttempts = 5;
|
|
180
|
+
let isReady = false;
|
|
181
|
+
|
|
182
|
+
while (attempts < maxAttempts && !isReady) {
|
|
183
|
+
try {
|
|
184
|
+
const validation = await axios.post(ALEX_ENGINE_URL, {
|
|
185
|
+
prompt: "ping", validateProject: true, checkNetwork: true
|
|
186
|
+
}, { headers: { 'x-project-id': projectId }, timeout: 5000 });
|
|
187
|
+
|
|
188
|
+
if (validation.data?.isRunning) { isReady = true; break; }
|
|
189
|
+
attempts++;
|
|
190
|
+
if (attempts < maxAttempts) await new Promise(r => setTimeout(r, 2000));
|
|
191
|
+
} catch (error) {
|
|
192
|
+
attempts++;
|
|
193
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
153
194
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (!isReady) {
|
|
198
|
+
console.error('\\\\n\\\\x1b[31mâš ï¸ ENGINE OFFLINE:\\\\x1b[0m Start Fleetbo runtime first: "npm run fleetbo" ');
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// --- INITIALISATION DE L'INTERFACE VISUELLE ---
|
|
203
|
+
process.stdout.write(' '.repeat(60) + '\\\\r'); // Efface le status de validation
|
|
204
|
+
|
|
205
|
+
// 1. Accueil Alex (Vert)
|
|
206
|
+
console.log('\\\\n\\\\x1b[32m🤖 Alex is now online.\\\\x1b[0m');
|
|
207
|
+
console.log('\\\\x1b[32mAlex â¯\\\\x1b[0m Welcome! I am Alex, your architect. What are we building today?');
|
|
208
|
+
|
|
209
|
+
// 2. Premier saut de ligne pour l'esthétique
|
|
210
|
+
console.log('');
|
|
211
|
+
|
|
212
|
+
// 3. Configuration du prompt Développeur (Bleu)
|
|
213
|
+
const userName = testerEmail ? testerEmail.split('@')[0] : 'Dev';
|
|
214
|
+
const rl = readline.createInterface({
|
|
215
|
+
input: process.stdin,
|
|
216
|
+
output: process.stdout,
|
|
217
|
+
prompt: \`\\\\x1b[34m\\\${userName} ⯠\\\\x1b[0m\`
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
rl.prompt();
|
|
221
|
+
|
|
222
|
+
rl.on('line', async (line) => {
|
|
223
|
+
if (['exit', 'quit'].includes(line.trim().toLowerCase())) {
|
|
224
|
+
console.log('\\\\n\\\\x1b[90mðŸ'‹ Alex session closed.\\\\x1b[0m');
|
|
225
|
+
rl.close();
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (line.trim()) {
|
|
230
|
+
await processAlexRequest(line.trim());
|
|
231
|
+
// ✅ SAUT DE LIGNE après la réponse d'Alex
|
|
232
|
+
console.log('');
|
|
233
|
+
}
|
|
234
|
+
|
|
157
235
|
rl.prompt();
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
rl.prompt();
|
|
162
|
-
}).on('close', () => { console.log('\\\\n👋 Alex going offline.'); process.exit(0); });
|
|
163
|
-
} catch (error) { process.exit(1); }
|
|
236
|
+
}).on('close', () => {
|
|
237
|
+
process.exit(0);
|
|
238
|
+
});
|
|
164
239
|
};
|
|
240
|
+
|
|
165
241
|
if (!initialPrompt || initialPrompt === '?') startAlexSession();
|
|
166
242
|
else processAlexRequest(initialPrompt);
|
|
167
243
|
return;
|
|
@@ -170,7 +246,7 @@ if (command === 'alex') {
|
|
|
170
246
|
if (command === 'deploy') {
|
|
171
247
|
checkGitSecurity();
|
|
172
248
|
(async () => {
|
|
173
|
-
console.log('\\\\n\\\\x1b[36m
|
|
249
|
+
console.log('\\\\n\\\\x1b[36mâš¡ FLEETBO CLOUD ENGINE\\\\x1b[0m');
|
|
174
250
|
try {
|
|
175
251
|
execSync('npm run build', { stdio: 'inherit' });
|
|
176
252
|
let buildDir = fs.existsSync(path.join(process.cwd(), 'dist')) ? 'dist' : 'build';
|
|
@@ -181,28 +257,34 @@ if (command === 'deploy') {
|
|
|
181
257
|
archive.directory(path.join(process.cwd(), buildDir), false);
|
|
182
258
|
archive.finalize();
|
|
183
259
|
});
|
|
184
|
-
console.log('\\\\
|
|
260
|
+
console.log('\\\\nðŸ"¦ \\\\x1b[33mPreparing Neural Logic for Uplink...\\\\x1b[0m');
|
|
185
261
|
await showEnergyTransfer();
|
|
186
262
|
await axios.post(CLOUD_ENGINE_URL, zipBuffer, { headers: { 'Content-Type': 'application/zip', 'x-project-id': projectId } });
|
|
187
|
-
console.log('\\\\n
|
|
263
|
+
console.log('\\\\n✅ \\\\x1b[1mDEPLOYMENT SUCCESSFUL\\\\x1b[0m | \\\\x1b[32mAlex â¯\\\\x1b[0m Runtime updated.');
|
|
188
264
|
} catch (error) { process.exit(1); }
|
|
189
265
|
})();
|
|
190
266
|
return;
|
|
191
267
|
}
|
|
192
268
|
|
|
269
|
+
// ==========================================
|
|
270
|
+
// 2. COMMANDE: GENERATE (Original préservé)
|
|
271
|
+
// ==========================================
|
|
193
272
|
const GENERATOR_COMMANDS = ['page', 'g', 'generate', 'android', 'ios'];
|
|
194
273
|
if (GENERATOR_COMMANDS.includes(command)) {
|
|
195
|
-
try { require('./page.js'); } catch (
|
|
274
|
+
try { require('./page.js'); } catch (e) { console.error(e.message); process.exit(1); }
|
|
196
275
|
return;
|
|
197
276
|
}
|
|
198
277
|
|
|
278
|
+
// ==========================================
|
|
279
|
+
// 3. COMMANDE: DEV / CLEANUP (Original préservé)
|
|
280
|
+
// ==========================================
|
|
199
281
|
const NULL_DEV = process.platform === 'win32' ? '>nul 2>&1' : '2>/dev/null';
|
|
200
282
|
|
|
201
283
|
function killProcessOnPort(port) {
|
|
202
284
|
try {
|
|
203
285
|
if (process.platform !== 'win32') {
|
|
204
286
|
const pid = execSync(\`lsof -ti:\\\${port} \\\${NULL_DEV}\`).toString().trim();
|
|
205
|
-
if (pid)
|
|
287
|
+
if (pid) execSync(\`kill -9 \\\${pid.split('\\\\n').join(' ')} \\\${NULL_DEV}\`);
|
|
206
288
|
}
|
|
207
289
|
} catch (e) {}
|
|
208
290
|
}
|
|
@@ -218,8 +300,9 @@ let isExiting = false;
|
|
|
218
300
|
async function cleanupAndExit(code = 0) {
|
|
219
301
|
if (isExiting) return;
|
|
220
302
|
isExiting = true;
|
|
303
|
+
console.log('\\\\n[Fleetbo] ðŸ›' Stopping environment...');
|
|
221
304
|
try {
|
|
222
|
-
await axios.post(UPDATE_NETWORK_URL, { keyApp
|
|
305
|
+
await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl: '', tester: testerEmail });
|
|
223
306
|
} catch (e) {}
|
|
224
307
|
killNetworkService();
|
|
225
308
|
killProcessOnPort(PORT);
|
|
@@ -231,28 +314,54 @@ process.on('SIGTERM', () => cleanupAndExit(0));
|
|
|
231
314
|
async function syncFirebase(keyApp, networkUrl, testerEmail) {
|
|
232
315
|
try {
|
|
233
316
|
await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl, tester: testerEmail });
|
|
234
|
-
|
|
235
|
-
console.log(
|
|
236
|
-
|
|
317
|
+
|
|
318
|
+
console.log(\`\\\\n\\\\x1b[32m[Fleetbo]\\\\x1b[0m -------------------------------------------------------------\`);
|
|
319
|
+
console.log('\\\\x1b[32m[Fleetbo] GO GO GO ! FLEETBO STUDIO IS READY \\\\x1b[0m');
|
|
320
|
+
console.log(\`\\\\x1b[32m[Fleetbo] Link: https://fleetbo.io/studio/\\\${keyApp}\\\\x1b[0m\`);
|
|
321
|
+
console.log('\\\\x1b[32m[Fleetbo] You can now start coding and previewing in Studio. 🚀\\\\x1b[0m');
|
|
322
|
+
console.log(\`\\\\x1b[32m[Fleetbo]\\\\x1b[0m -------------------------------------------------------------\`);
|
|
323
|
+
} catch (err) {
|
|
324
|
+
console.error(\`[Fleetbo] ⌠Sync Error: \\\${err.message}\`);
|
|
325
|
+
}
|
|
237
326
|
}
|
|
238
327
|
|
|
239
328
|
async function runDevEnvironment() {
|
|
329
|
+
console.log(\`[Fleetbo] ðŸ›¡ï¸ Initializing Dev Environment...\`);
|
|
240
330
|
killNetworkService();
|
|
241
331
|
killProcessOnPort(PORT);
|
|
332
|
+
if (!testerEmail) { console.error('Error: REACT_APP_TESTER_EMAIL missing'); process.exit(1); }
|
|
333
|
+
|
|
242
334
|
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
243
|
-
const devServer = spawn(npmCmd, ['start'], {
|
|
335
|
+
const devServer = spawn(npmCmd, ['start'], {
|
|
336
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
337
|
+
shell: true,
|
|
338
|
+
env: { ...process.env, BROWSER: 'none', PORT: PORT.toString() }
|
|
339
|
+
});
|
|
340
|
+
devServer.stdout.pipe(process.stdout);
|
|
341
|
+
devServer.stderr.pipe(process.stderr);
|
|
342
|
+
|
|
343
|
+
let connectionStarted = false;
|
|
244
344
|
devServer.stdout.on('data', (data) => {
|
|
245
345
|
const output = data.toString();
|
|
246
|
-
if (output.includes('Local:') || output.includes('Compiled successfully')) {
|
|
346
|
+
if (!connectionStarted && (output.includes('Local:') || output.includes('Compiled successfully'))) {
|
|
347
|
+
connectionStarted = true;
|
|
348
|
+
|
|
349
|
+
console.log('\\\\n[Fleetbo] ---------------------------------------------------');
|
|
350
|
+
console.log(\`[Fleetbo] 🔗 Establishing Secure Uplink...\`);
|
|
351
|
+
console.log(\`[Fleetbo] 🛑 DO NOT open the Fleetbo Studio yet. \`);
|
|
352
|
+
console.log(\`[Fleetbo] ⏳ Please wait green message...\`);
|
|
353
|
+
console.log('[Fleetbo] ---------------------------------------------------');
|
|
354
|
+
|
|
247
355
|
const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
248
356
|
const uplink = spawn(npxCmd, ['cloudflared', 'tunnel', '--url', \`http://localhost:\\\${PORT}\`], { shell: true });
|
|
249
357
|
uplink.stderr.on('data', (chunk) => {
|
|
250
|
-
const match =
|
|
358
|
+
const match = chunk.toString().match(/https:\\\\/\\\\/[a-zA-Z0-9-]+\\\\.trycloudflare\\\\.com/);
|
|
251
359
|
if (match) syncFirebase(keyApp, match[0], testerEmail);
|
|
252
360
|
});
|
|
253
361
|
}
|
|
254
362
|
});
|
|
255
363
|
}
|
|
364
|
+
|
|
256
365
|
runDevEnvironment();
|
|
257
366
|
`;
|
|
258
367
|
|
|
@@ -266,7 +375,7 @@ const bootstrapTokenArg = tokenArg ? tokenArg.split('=')[1] : null;
|
|
|
266
375
|
const userEmailArg = emailArg ? emailArg.split('=')[1] : null;
|
|
267
376
|
|
|
268
377
|
if (!projectNameArg || !bootstrapTokenArg || !userEmailArg) {
|
|
269
|
-
console.error('\n
|
|
378
|
+
console.error('\n Usage: npx create-fleetbo-project <name> --token=<token> --email=<email>');
|
|
270
379
|
process.exit(1);
|
|
271
380
|
}
|
|
272
381
|
|
|
@@ -320,17 +429,17 @@ function downloadEngine(url, dest) {
|
|
|
320
429
|
}
|
|
321
430
|
|
|
322
431
|
async function setupProject() {
|
|
323
|
-
console.log(`\n
|
|
432
|
+
console.log(`\nâš¡ Initializing Fleetbo Framework for "${projectName}"...`);
|
|
324
433
|
|
|
325
434
|
try {
|
|
326
435
|
if (fs.existsSync(projectDir)) throw new Error(`Directory "${projectName}" already exists.`);
|
|
327
436
|
fs.mkdirSync(projectDir);
|
|
328
437
|
|
|
329
|
-
console.log(' [1/6]
|
|
438
|
+
console.log(' [1/6]---------- Downloading Fleetbo Core Engine...');
|
|
330
439
|
const archivePath = path.join(projectDir, 'engine.tar.gz');
|
|
331
440
|
await downloadEngine(archiveUrl, archivePath);
|
|
332
441
|
|
|
333
|
-
console.log(' [2/6]
|
|
442
|
+
console.log(' [2/6]---------- Scaffolding project structure...');
|
|
334
443
|
try {
|
|
335
444
|
execSync(`tar -xf "${archivePath}" -C "${projectDir}" --strip-components=1`, { stdio: 'ignore' });
|
|
336
445
|
fs.unlinkSync(archivePath);
|
|
@@ -338,23 +447,22 @@ async function setupProject() {
|
|
|
338
447
|
|
|
339
448
|
process.chdir(projectDir);
|
|
340
449
|
|
|
341
|
-
console.log(' [3/6]
|
|
450
|
+
console.log(' [3/6]---------- Authenticating with Fleetbo Cloud...');
|
|
342
451
|
const keys = await fetchProjectKeys(bootstrapTokenArg);
|
|
343
452
|
if (!keys.enterpriseId) throw new Error("Invalid keys.");
|
|
344
453
|
|
|
345
|
-
console.log(' [4.1/6]
|
|
454
|
+
console.log(' [4.1/6]---------- Configuring environment & CLI...');
|
|
346
455
|
|
|
347
|
-
// Correction indentation .env
|
|
348
456
|
const envContent = `REACT_APP_FLEETBO_DB_KEY=${keys.fleetboDBKey}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
457
|
+
REACT_APP_ENTERPRISE_ID=${keys.enterpriseId}
|
|
458
|
+
REACT_KEY_APP=${projectName}
|
|
459
|
+
REACT_APP_TESTER_EMAIL=${userEmailArg}
|
|
460
|
+
DANGEROUSLY_DISABLE_HOST_CHECK=true
|
|
461
|
+
WDS_SOCKET_PORT=0`;
|
|
354
462
|
|
|
355
463
|
fs.writeFileSync(path.join(projectDir, '.env'), envContent, 'utf8');
|
|
356
464
|
|
|
357
|
-
console.log(' [4.2/6]
|
|
465
|
+
console.log(' [4.2/6]---------- Securing environment (adding .gitignore)...');
|
|
358
466
|
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`;
|
|
359
467
|
fs.writeFileSync(path.join(projectDir, '.gitignore'), gitignoreContent, 'utf8');
|
|
360
468
|
|
|
@@ -363,22 +471,22 @@ async function setupProject() {
|
|
|
363
471
|
fs.writeFileSync(path.join(scriptsDir, 'cli.js'), CLI_SCRIPT_CONTENT, 'utf8');
|
|
364
472
|
try { fs.chmodSync(path.join(scriptsDir, 'cli.js'), '755'); } catch (e) {}
|
|
365
473
|
|
|
366
|
-
console.log(' [5/6]
|
|
474
|
+
console.log(' [5/6]---------- Installing dependencies...');
|
|
367
475
|
execSync('npm install', { stdio: 'inherit' });
|
|
368
476
|
execSync('npm install cloudflared dotenv axios archiver --save-dev', { stdio: 'ignore' });
|
|
369
477
|
|
|
370
|
-
console.log(' [6/6]
|
|
478
|
+
console.log(' [6/6]---------- Finalizing setup...');
|
|
371
479
|
const packageJsonPath = path.join(projectDir, 'package.json');
|
|
372
480
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
373
481
|
packageJson.name = projectName;
|
|
374
482
|
packageJson.scripts = { ...packageJson.scripts, "fleetbo": "node scripts/cli.js", "dev": "node scripts/cli.js" };
|
|
375
483
|
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8');
|
|
376
484
|
|
|
377
|
-
console.log('\n [Fleetbo]
|
|
378
|
-
console.log(`\
|
|
485
|
+
console.log('\n [Fleetbo] Project successfully created!');
|
|
486
|
+
console.log(`\nðŸ'‰ Run: cd ${projectName} && npm run fleetbo`);
|
|
379
487
|
|
|
380
488
|
} catch (error) {
|
|
381
|
-
console.error('\
|
|
489
|
+
console.error('\n⌠Setup failed:', error.message);
|
|
382
490
|
if (fs.existsSync(projectDir)) try { fs.rmSync(projectDir, { recursive: true, force: true }); } catch(e){}
|
|
383
491
|
process.exit(1);
|
|
384
492
|
}
|