create-fleetbo-project 1.2.42 → 1.2.43
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 +53 -53
- package/package.json +1 -1
|
@@ -34,7 +34,7 @@ const command = args[0];
|
|
|
34
34
|
process.env.DOTENV_SILENT = 'true';
|
|
35
35
|
const envPath = path.join(process.cwd(), '.env');
|
|
36
36
|
if (!fs.existsSync(envPath)) {
|
|
37
|
-
console.error('
|
|
37
|
+
console.error('\\x1b[31m%s\\x1b[0m', '❌ Error: Configuration file (.env) not found.');
|
|
38
38
|
process.exit(1);
|
|
39
39
|
}
|
|
40
40
|
dotenv.config({ path: envPath, quiet: true });
|
|
@@ -48,19 +48,19 @@ const checkGitSecurity = () => {
|
|
|
48
48
|
const gitignorePath = path.join(process.cwd(), '.gitignore');
|
|
49
49
|
if (fs.existsSync(gitDir)) {
|
|
50
50
|
if (!fs.existsSync(gitignorePath)) {
|
|
51
|
-
console.error('
|
|
51
|
+
console.error('\\n\\x1b[31m🚨 SECURITY ALERT:\\x1b[0m .git detected but no .gitignore found.');
|
|
52
52
|
process.exit(1);
|
|
53
53
|
}
|
|
54
54
|
const gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
|
|
55
55
|
if (!gitignoreContent.includes('.env')) {
|
|
56
|
-
console.error('
|
|
56
|
+
console.error('\\n\\x1b[31m🚨 CRITICAL RISK:\\x1b[0m .env is NOT ignored by Git.');
|
|
57
57
|
process.exit(1);
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
if (!projectId) {
|
|
63
|
-
console.error('
|
|
63
|
+
console.error('\\n❌ Error: Project ID missing in .env.\\n');
|
|
64
64
|
process.exit(1);
|
|
65
65
|
}
|
|
66
66
|
|
|
@@ -73,17 +73,17 @@ const injectRouteIntoAppJs = (pageName, subPath = '') => {
|
|
|
73
73
|
|
|
74
74
|
if (!content.includes(alexRouteAnchor)) return false;
|
|
75
75
|
|
|
76
|
-
const pathPrefix = subPath ?
|
|
77
|
-
const importLine =
|
|
78
|
-
const routeLine =
|
|
76
|
+
const pathPrefix = subPath ? \`\${subPath}/\` : '';
|
|
77
|
+
const importLine = \`import \${pageName} from './pages/\${pathPrefix}\${pageName}';\`;
|
|
78
|
+
const routeLine = \`<Route path="/\${pathPrefix.toLowerCase()}\${pageName.toLowerCase()}" element=<\${\${pageName} />} />\`;
|
|
79
79
|
|
|
80
80
|
let injected = false;
|
|
81
81
|
if (!content.includes(importLine)) {
|
|
82
|
-
content = content.replace(importAnchor,
|
|
82
|
+
content = content.replace(importAnchor, \`\${importLine}\\n\${importAnchor}\`);
|
|
83
83
|
injected = true;
|
|
84
84
|
}
|
|
85
85
|
if (!content.includes(routeLine)) {
|
|
86
|
-
content = content.replace(alexRouteAnchor,
|
|
86
|
+
content = content.replace(alexRouteAnchor, \`\${routeLine}\\n \${alexRouteAnchor}\`);
|
|
87
87
|
injected = true;
|
|
88
88
|
}
|
|
89
89
|
|
|
@@ -95,10 +95,10 @@ const showEnergyTransfer = async () => {
|
|
|
95
95
|
const width = 30;
|
|
96
96
|
for (let i = 0; i <= width; i++) {
|
|
97
97
|
const dots = "█".repeat(i); const empty = "░".repeat(width - i);
|
|
98
|
-
process.stdout.write(
|
|
98
|
+
process.stdout.write(\`\\r \\x1b[32m⚡ Alex Energy Sync:\\x1b[0m [\${dots}\${empty}] \${Math.round((i / width) * 100)}%\`);
|
|
99
99
|
await new Promise(r => setTimeout(r, 45));
|
|
100
100
|
}
|
|
101
|
-
process.stdout.write('
|
|
101
|
+
process.stdout.write('\\n');
|
|
102
102
|
};
|
|
103
103
|
|
|
104
104
|
if (command === 'alex') {
|
|
@@ -106,43 +106,43 @@ if (command === 'alex') {
|
|
|
106
106
|
const initialPrompt = args.slice(1).join(' ');
|
|
107
107
|
|
|
108
108
|
const processAlexRequest = async (prompt) => {
|
|
109
|
-
process.stdout.write('
|
|
109
|
+
process.stdout.write('\\x1b[33m🧠 Alex is thinking...\\x1b[0m');
|
|
110
110
|
try {
|
|
111
111
|
const result = await axios.post(ALEX_ENGINE_URL, { prompt, projectType: 'android' }, {
|
|
112
112
|
headers: { 'x-project-id': projectId }
|
|
113
113
|
});
|
|
114
114
|
|
|
115
115
|
const aiData = result.data;
|
|
116
|
-
process.stdout.write('
|
|
116
|
+
process.stdout.write('\\r' + ' '.repeat(50) + '\\r');
|
|
117
117
|
|
|
118
118
|
if (aiData.status === 'quota_exceeded') {
|
|
119
|
-
console.log(
|
|
119
|
+
console.log(\`\\n\\x1b[31m⛔ ENGINE OUT OF FUEL:\\x1b[0m \${aiData.message}\`);
|
|
120
120
|
return;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
if (aiData.status === 'success' || aiData.status === 'message') {
|
|
124
124
|
console.log('');
|
|
125
|
-
console.log(
|
|
125
|
+
console.log(\`\\x1b[32mAlex ❯\\x1b[0m \${aiData.message || "I'm ready."}\`);
|
|
126
126
|
|
|
127
127
|
if (aiData.remainingTokens !== undefined) {
|
|
128
128
|
const remaining = aiData.remainingTokens;
|
|
129
129
|
const limit = aiData.limit || 2500;
|
|
130
130
|
const percent = Math.round((remaining / limit) * 100);
|
|
131
|
-
const energyColor = percent > 30 ? '
|
|
132
|
-
console.log(
|
|
131
|
+
const energyColor = percent > 30 ? '\\x1b[32m' : '\\x1b[31m';
|
|
132
|
+
console.log(\`\\x1b[36m📊 Energy:\\x1b[0m \${energyColor}\${percent}%\\x1b[0m (\${remaining}/\${limit} tokens left)\`);
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
if (aiData.status === 'success' && aiData.moduleData) {
|
|
137
137
|
const { fileName, code, mockFileName, mockCode, moduleName } = aiData.moduleData;
|
|
138
|
-
console.log(
|
|
138
|
+
console.log(\` \\x1b[90m⚙️ Architecting: \${moduleName}\\x1b[0m\`);
|
|
139
139
|
|
|
140
140
|
const writeFile = (dir, name, content) => {
|
|
141
141
|
const fullPath = path.join(process.cwd(), dir);
|
|
142
142
|
const filePath = path.join(fullPath, name);
|
|
143
143
|
if (!fs.existsSync(fullPath)) fs.mkdirSync(fullPath, { recursive: true });
|
|
144
144
|
fs.writeFileSync(filePath, content);
|
|
145
|
-
console.log(
|
|
145
|
+
console.log(\` ✅ \\x1b[32m[Written]\\x1b[0m \${dir}\${name}\`);
|
|
146
146
|
};
|
|
147
147
|
|
|
148
148
|
if (code && fileName) {
|
|
@@ -156,13 +156,13 @@ if (command === 'alex') {
|
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
} catch (error) {
|
|
159
|
-
process.stdout.write('
|
|
160
|
-
console.error('
|
|
159
|
+
process.stdout.write('\\r' + ' '.repeat(50) + '\\r');
|
|
160
|
+
console.error('\\n\\x1b[31m❌ Alex Error:\\x1b[0m ' + (error.response?.data?.message || error.message));
|
|
161
161
|
}
|
|
162
162
|
};
|
|
163
163
|
|
|
164
164
|
const startAlexSession = async () => {
|
|
165
|
-
process.stdout.write('
|
|
165
|
+
process.stdout.write('\\x1b[33m🛡️ Alex is checking runtime state...\\x1b[0m\\r');
|
|
166
166
|
let attempts = 0; const maxAttempts = 5; let isReady = false;
|
|
167
167
|
while (attempts < maxAttempts && !isReady) {
|
|
168
168
|
try {
|
|
@@ -172,17 +172,17 @@ if (command === 'alex') {
|
|
|
172
172
|
} catch (error) { attempts++; await new Promise(r => setTimeout(r, 2000)); }
|
|
173
173
|
}
|
|
174
174
|
if (!isReady) {
|
|
175
|
-
console.error('
|
|
175
|
+
console.error('\\n\\x1b[31m⚠️ ENGINE OFFLINE:\\x1b[0m Start Fleetbo runtime first: "npm run fleetbo" ');
|
|
176
176
|
process.exit(1);
|
|
177
177
|
}
|
|
178
|
-
process.stdout.write(' '.repeat(60) + '
|
|
179
|
-
console.log('
|
|
180
|
-
console.log('
|
|
178
|
+
process.stdout.write(' '.repeat(60) + '\\r');
|
|
179
|
+
console.log('\\n\\x1b[32m🤖 Alex is now online.\\x1b[0m');
|
|
180
|
+
console.log('\\x1b[32mAlex ❯\\x1b[0m Welcome! I am Alex, your architect. What are we building today?\\n');
|
|
181
181
|
const userName = testerEmail ? testerEmail.split('@')[0] : 'Dev';
|
|
182
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout, prompt:
|
|
182
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout, prompt: \`\\x1b[34m\${userName} ❯ \\x1b[0m\` });
|
|
183
183
|
rl.prompt();
|
|
184
184
|
rl.on('line', async (line) => {
|
|
185
|
-
if (['exit', 'quit'].includes(line.trim().toLowerCase())) { console.log('
|
|
185
|
+
if (['exit', 'quit'].includes(line.trim().toLowerCase())) { console.log('\\n\\x1b[90m👋 Alex session closed.\\x1b[0m'); rl.close(); return; }
|
|
186
186
|
if (line.trim()) { await processAlexRequest(line.trim()); console.log(''); }
|
|
187
187
|
rl.prompt();
|
|
188
188
|
}).on('close', () => { process.exit(0); });
|
|
@@ -196,7 +196,7 @@ if (command === 'alex') {
|
|
|
196
196
|
if (command === 'deploy') {
|
|
197
197
|
checkGitSecurity();
|
|
198
198
|
(async () => {
|
|
199
|
-
console.log('
|
|
199
|
+
console.log('\\n\\x1b[36m⚡ FLEETBO CLOUD ENGINE\\x1b[0m');
|
|
200
200
|
try {
|
|
201
201
|
execSync('npm run build', { stdio: 'inherit' });
|
|
202
202
|
let buildDir = fs.existsSync(path.join(process.cwd(), 'dist')) ? 'dist' : 'build';
|
|
@@ -207,10 +207,10 @@ if (command === 'deploy') {
|
|
|
207
207
|
archive.directory(path.join(process.cwd(), buildDir), false);
|
|
208
208
|
archive.finalize();
|
|
209
209
|
});
|
|
210
|
-
console.log('
|
|
210
|
+
console.log('\\n📦 \\x1b[33mPreparing Neural Logic for Uplink...\\x1b[0m');
|
|
211
211
|
await showEnergyTransfer();
|
|
212
212
|
await axios.post(CLOUD_ENGINE_URL, zipBuffer, { headers: { 'Content-Type': 'application/zip', 'x-project-id': projectId } });
|
|
213
|
-
console.log('
|
|
213
|
+
console.log('\\n✅ \\x1b[1mDEPLOYMENT SUCCESSFUL\\x1b[0m | \\x1b[32mAlex ❯\\x1b[0m Runtime updated.');
|
|
214
214
|
} catch (error) { process.exit(1); }
|
|
215
215
|
})();
|
|
216
216
|
return;
|
|
@@ -226,8 +226,8 @@ const NULL_DEV = process.platform === 'win32' ? '>nul 2>&1' : '2>/dev/null';
|
|
|
226
226
|
function killProcessOnPort(port) {
|
|
227
227
|
try {
|
|
228
228
|
if (process.platform !== 'win32') {
|
|
229
|
-
const pid = execSync(
|
|
230
|
-
if (pid) execSync(
|
|
229
|
+
const pid = execSync(\`lsof -ti:\${port} \${NULL_DEV}\`).toString().trim();
|
|
230
|
+
if (pid) execSync(\`kill -9 \${pid.split('\\n').join(' ')} \${NULL_DEV}\`);
|
|
231
231
|
}
|
|
232
232
|
} catch (e) {}
|
|
233
233
|
}
|
|
@@ -241,7 +241,7 @@ function killNetworkService() {
|
|
|
241
241
|
let isExiting = false;
|
|
242
242
|
async function cleanupAndExit(code = 0) {
|
|
243
243
|
if (isExiting) return; isExiting = true;
|
|
244
|
-
console.log('
|
|
244
|
+
console.log('\\n[Fleetbo] 🛑 Stopping environment...');
|
|
245
245
|
try { await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl: '', tester: testerEmail }); } catch (e) {}
|
|
246
246
|
killNetworkService(); killProcessOnPort(PORT); process.exit(code);
|
|
247
247
|
}
|
|
@@ -251,16 +251,16 @@ process.on('SIGTERM', () => cleanupAndExit(0));
|
|
|
251
251
|
async function syncFirebase(keyApp, networkUrl, testerEmail) {
|
|
252
252
|
try {
|
|
253
253
|
await axios.post(UPDATE_NETWORK_URL, { keyApp, networkUrl, tester: testerEmail });
|
|
254
|
-
console.log(
|
|
255
|
-
console.log('
|
|
256
|
-
console.log(
|
|
257
|
-
console.log('
|
|
258
|
-
console.log(
|
|
259
|
-
} catch (err) { console.error(
|
|
254
|
+
console.log(\`\\n\\x1b[32m[Fleetbo]\\x1b[0m -------------------------------------------------------------\`);
|
|
255
|
+
console.log('\\x1b[32m[Fleetbo] GO GO GO ! FLEETBO STUDIO IS READY \\x1b[0m');
|
|
256
|
+
console.log(\`\\x1b[32m[Fleetbo] Link: https://fleetbo.io/studio/\${keyApp}\\x1b[0m\`);
|
|
257
|
+
console.log('\\x1b[32m[Fleetbo] You can now start coding and previewing in Studio. 🚀\\x1b[0m');
|
|
258
|
+
console.log(\`\\x1b[32m[Fleetbo]\\x1b[0m -------------------------------------------------------------\`);
|
|
259
|
+
} catch (err) { console.error(\`[Fleetbo] ❌ Sync Error: \${err.message}\`); }
|
|
260
260
|
}
|
|
261
261
|
|
|
262
262
|
async function runDevEnvironment() {
|
|
263
|
-
console.log(
|
|
263
|
+
console.log(\`[Fleetbo] 🛡️ Initializing Dev Environment...\`);
|
|
264
264
|
killNetworkService(); killProcessOnPort(PORT);
|
|
265
265
|
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
266
266
|
const devServer = spawn(npmCmd, ['start'], { stdio: ['ignore', 'pipe', 'pipe'], shell: true, env: { ...process.env, BROWSER: 'none', PORT: PORT.toString() } });
|
|
@@ -270,18 +270,18 @@ async function runDevEnvironment() {
|
|
|
270
270
|
const output = data.toString();
|
|
271
271
|
if (!connectionStarted && (output.includes('Local:') || output.includes('Compiled successfully'))) {
|
|
272
272
|
connectionStarted = true;
|
|
273
|
-
console.log('
|
|
274
|
-
console.log(
|
|
273
|
+
console.log('\\n[Fleetbo] ---------------------------------------------------');
|
|
274
|
+
console.log(\`[Fleetbo] 🔗 Establishing Secure Uplink...\\n[Fleetbo] 🛑 DO NOT open the Fleetbo Studio yet.\\n[Fleetbo] ⏳ Please wait green message...\\n[Fleetbo] ---------------------------------------------------\`);
|
|
275
275
|
const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
276
|
-
const uplink = spawn(npxCmd, ['cloudflared', 'tunnel', '--url',
|
|
276
|
+
const uplink = spawn(npxCmd, ['cloudflared', 'tunnel', '--url', \`http://localhost:\${PORT}\`], { shell: true });
|
|
277
277
|
uplink.stderr.on('data', (chunk) => {
|
|
278
|
-
const match = chunk.toString().match(/https
|
|
278
|
+
const match = chunk.toString().match(/https:\\/\\/[a-zA-Z0-9-]+\\.trycloudflare\\.com/);
|
|
279
279
|
if (match) syncFirebase(keyApp, match[0], testerEmail);
|
|
280
280
|
});
|
|
281
281
|
}
|
|
282
282
|
});
|
|
283
283
|
}
|
|
284
|
-
runDevEnvironment()
|
|
284
|
+
runDevEnvironment();`.replace(/`/g, '\\`').replace(/\${/g, '\\${');
|
|
285
285
|
|
|
286
286
|
|
|
287
287
|
const args = process.argv.slice(2);
|
|
@@ -353,11 +353,11 @@ async function setupProject() {
|
|
|
353
353
|
if (fs.existsSync(projectDir)) throw new Error(`Directory "${projectName}" already exists.`);
|
|
354
354
|
fs.mkdirSync(projectDir);
|
|
355
355
|
|
|
356
|
-
console.log(' [1/
|
|
356
|
+
console.log(' [1/7] 📥 Downloading Fleetbo Core Engine...');
|
|
357
357
|
const archivePath = path.join(projectDir, 'engine.tar.gz');
|
|
358
358
|
await downloadEngine(archiveUrl, archivePath);
|
|
359
359
|
|
|
360
|
-
console.log(' [2/
|
|
360
|
+
console.log(' [2/7] 📦 Scaffolding project structure...');
|
|
361
361
|
try {
|
|
362
362
|
execSync(`tar -xf "${archivePath}" -C "${projectDir}" --strip-components=1`, { stdio: 'ignore' });
|
|
363
363
|
fs.unlinkSync(archivePath);
|
|
@@ -365,11 +365,11 @@ async function setupProject() {
|
|
|
365
365
|
|
|
366
366
|
process.chdir(projectDir);
|
|
367
367
|
|
|
368
|
-
console.log(' [3/
|
|
368
|
+
console.log(' [3/7] 🔑 Authenticating with Fleetbo Cloud...');
|
|
369
369
|
const keys = await fetchProjectKeys(bootstrapTokenArg);
|
|
370
370
|
if (!keys.enterpriseId) throw new Error("Invalid keys.");
|
|
371
371
|
|
|
372
|
-
console.log(' [4
|
|
372
|
+
console.log(' [4/7] ⚙️ Configuring environment & CLI...');
|
|
373
373
|
|
|
374
374
|
// Correction indentation .env
|
|
375
375
|
const envContent = `REACT_APP_FLEETBO_DB_KEY=${keys.fleetboDBKey}
|
|
@@ -381,7 +381,7 @@ async function setupProject() {
|
|
|
381
381
|
|
|
382
382
|
fs.writeFileSync(path.join(projectDir, '.env'), envContent, 'utf8');
|
|
383
383
|
|
|
384
|
-
console.log(' [
|
|
384
|
+
console.log(' [5/7] 🛡️ Securing environment (adding .gitignore)...');
|
|
385
385
|
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
386
|
fs.writeFileSync(path.join(projectDir, '.gitignore'), gitignoreContent, 'utf8');
|
|
387
387
|
|
|
@@ -390,11 +390,11 @@ async function setupProject() {
|
|
|
390
390
|
fs.writeFileSync(path.join(scriptsDir, 'cli.js'), CLI_SCRIPT_CONTENT, 'utf8');
|
|
391
391
|
try { fs.chmodSync(path.join(scriptsDir, 'cli.js'), '755'); } catch (e) {}
|
|
392
392
|
|
|
393
|
-
console.log(' [
|
|
393
|
+
console.log(' [6/7] 📚 Installing dependencies...');
|
|
394
394
|
execSync('npm install', { stdio: 'inherit' });
|
|
395
395
|
execSync('npm install cloudflared dotenv axios archiver --save-dev', { stdio: 'ignore' });
|
|
396
396
|
|
|
397
|
-
console.log(' [
|
|
397
|
+
console.log(' [7/7] ✨ Finalizing setup...');
|
|
398
398
|
const packageJsonPath = path.join(projectDir, 'package.json');
|
|
399
399
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
400
400
|
packageJson.name = projectName;
|