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