devtunnel-cli 3.0.0 → 3.0.2

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/README.md CHANGED
@@ -11,19 +11,27 @@
11
11
 
12
12
  ## ⚔ Quick Start
13
13
 
14
- ### Windows
14
+ ### Option 1: Install via npm (Recommended)
15
+ ```bash
16
+ npm install -g devtunnel-cli
17
+ devtunnel
18
+ ```
19
+
20
+ ### Option 2: Download from GitHub
21
+
22
+ **Windows:**
15
23
  Double-click `START.bat`
16
24
 
17
- ### macOS
25
+ **macOS:**
18
26
  Double-click `START.command`
19
27
 
20
- ### Linux
28
+ **Linux:**
21
29
  ```bash
22
30
  chmod +x START.sh
23
31
  ./START.sh
24
32
  ```
25
33
 
26
- Or use npm:
34
+ **Or use npm:**
27
35
  ```bash
28
36
  npm start
29
37
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devtunnel-cli",
3
- "version": "3.0.0",
3
+ "version": "3.0.2",
4
4
  "type": "module",
5
5
  "description": "Share local dev servers worldwide - Zero config tunnel for any framework",
6
6
  "main": "src/core/start.js",
package/src/core/RUN.js CHANGED
@@ -9,11 +9,11 @@ import { dirname, join } from "path";
9
9
  const __filename = fileURLToPath(import.meta.url);
10
10
  const __dirname = dirname(__filename);
11
11
 
12
- console.log("\nšŸš€ DevTunnel - Universal Launcher\n");
13
- console.log(`šŸ“ Platform detected: ${platform()}\n`);
12
+ // Silent launcher - no output needed
14
13
 
15
14
  // Start the main app
16
- const startPath = join(__dirname, "src", "core", "start.js");
15
+ // start.js is in the same directory as RUN.js (src/core/)
16
+ const startPath = join(__dirname, "start.js");
17
17
  const child = spawn("node", [startPath], {
18
18
  stdio: "inherit",
19
19
  shell: false
package/src/core/index.js CHANGED
@@ -28,13 +28,12 @@ if (!PORT || isNaN(PORT) || PORT < 1 || PORT > 65535) {
28
28
  let tunnelProcess;
29
29
  let currentTunnelType = null;
30
30
 
31
- console.log("╔════════════════════════════════════════════╗");
32
- console.log("ā•‘ 🌐 DevTunnel v3.0 ā•‘");
33
- console.log("╠════════════════════════════════════════════╣");
34
- console.log(`ā•‘ šŸ“¦ ${PROJECT_NAME.padEnd(38)} ā•‘`);
35
- console.log(`ā•‘ šŸ”Œ Port: ${PORT.toString().padEnd(34)} ā•‘`);
36
- console.log("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•\n");
37
- console.log("šŸ’” Ensure dev server is running on port " + PORT + "\n");
31
+ console.log("DevTunnel Tunnel Service");
32
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
33
+ console.log(`Project: ${PROJECT_NAME}`);
34
+ console.log(`Port: ${PORT}`);
35
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
36
+ console.log("Ensure dev server is running on port " + PORT + "\n");
38
37
 
39
38
  // Check if project is Vite and auto-fix config for Cloudflare
40
39
  async function fixViteConfigForCloudflare() {
@@ -171,13 +170,13 @@ const TUNNEL_SERVICES = [
171
170
  }
172
171
  },
173
172
  needsViteFix: false,
174
- warning: "āš ļø Note: LocalTunnel shows a password page on first visit (uses your public IP)"
173
+ warning: "Note: LocalTunnel shows a password page on first visit (uses your public IP)"
175
174
  }
176
175
  ];
177
176
 
178
177
  // Try each tunnel service
179
178
  async function tryTunnelServices() {
180
- console.log("šŸ” Checking available tunnel services...\n");
179
+ console.log("Checking available tunnel services...\n");
181
180
 
182
181
  let hasCloudflare = false;
183
182
 
@@ -191,15 +190,15 @@ async function tryTunnelServices() {
191
190
 
192
191
  // Show tip if Cloudflare not installed
193
192
  if (!hasCloudflare) {
194
- console.log("šŸ’” TIP: Install Cloudflare for best experience (no password, fastest)");
195
- console.log(" → winget install Cloudflare.cloudflared\n");
193
+ console.log("TIP: Install Cloudflare for best experience (no password, fastest)");
194
+ console.log(" winget install Cloudflare.cloudflared\n");
196
195
  }
197
196
 
198
197
  for (const service of TUNNEL_SERVICES) {
199
198
  const available = await service.available();
200
199
 
201
200
  if (available) {
202
- console.log(`āœ… ${service.name} is available`);
201
+ console.log(`${service.name} is available`);
203
202
 
204
203
  // Show warning if exists
205
204
  if (service.warning) {
@@ -208,7 +207,7 @@ async function tryTunnelServices() {
208
207
 
209
208
  // Skip Vite auto-fix - using proxy server instead
210
209
 
211
- console.log(`🌐 Starting ${service.name} tunnel...\n`);
210
+ console.log(`Starting ${service.name} tunnel...\n`);
212
211
 
213
212
  currentTunnelType = service.name;
214
213
  tunnelProcess = spawn(service.command, service.args, {
@@ -223,25 +222,25 @@ async function tryTunnelServices() {
223
222
 
224
223
  // Check if process is still running
225
224
  if (tunnelProcess && !tunnelProcess.killed) {
226
- console.log(`\nāœ… Successfully connected via ${service.name}!`);
225
+ console.log(`Successfully connected via ${service.name}!`);
227
226
  if (service.name === "LocalTunnel") {
228
- console.log("šŸ’” First-time visitors need to enter tunnel password (your public IP)");
229
- console.log("šŸ’” Get password at: https://loca.lt/mytunnelpassword\n");
227
+ console.log("Note: First-time visitors need to enter tunnel password (your public IP)");
228
+ console.log("Get password at: https://loca.lt/mytunnelpassword\n");
230
229
  }
231
230
  console.log("Press Ctrl+C to stop the tunnel\n");
232
231
  return true;
233
232
  }
234
233
  } else {
235
- console.log(`āš ļø ${service.name} not available`);
234
+ console.log(`${service.name} not available`);
236
235
  }
237
236
  }
238
237
 
239
- console.log("\nāŒ No tunnel services available!");
240
- console.log("\nšŸ’” Recommended: Install Cloudflare (fastest, no password):");
238
+ console.log("\nNo tunnel services available!");
239
+ console.log("\nRecommended: Install Cloudflare (fastest, no password):");
241
240
  console.log(" winget install Cloudflare.cloudflared");
242
- console.log("\nšŸ’” Or install Ngrok:");
241
+ console.log("\nOr install Ngrok:");
243
242
  console.log(" Download from: https://ngrok.com/download");
244
- console.log("\nšŸ’” LocalTunnel is already installed but may require restart");
243
+ console.log("\nLocalTunnel is already installed but may require restart");
245
244
  process.exit(1);
246
245
  }
247
246
 
@@ -264,22 +263,11 @@ function setupTunnelHandlers(serviceName) {
264
263
  const urlMatch = trimmed.match(/(https?:\/\/[^\s]+trycloudflare\.com[^\s]*)/);
265
264
  if (urlMatch) {
266
265
  const url = urlMatch[1];
267
- const minWidth = 60;
268
- const urlLength = url.length + 4; // 2 spaces on each side + "ā•‘"
269
- const boxWidth = Math.max(minWidth, urlLength);
270
-
271
- console.log("\nā•”" + "═".repeat(boxWidth) + "ā•—");
272
- const headerText = "āœ… PUBLIC URL";
273
- const headerPadding = boxWidth - headerText.length;
274
- console.log("ā•‘ " + headerText + " ".repeat(Math.max(0, headerPadding)) + "ā•‘");
275
- console.log("ā• " + "═".repeat(boxWidth) + "ā•£");
276
- const urlPadding = boxWidth - url.length;
277
- console.log("ā•‘ " + url + " ".repeat(Math.max(0, urlPadding)) + "ā•‘");
278
- console.log("ā• " + "═".repeat(boxWidth) + "ā•£");
279
- const shareText = "šŸ’” Share this URL with anyone!";
280
- const sharePadding = boxWidth - shareText.length;
281
- console.log("ā•‘ " + shareText + " ".repeat(Math.max(0, sharePadding)) + "ā•‘");
282
- console.log("ā•š" + "═".repeat(boxWidth) + "ā•\n");
266
+ console.log("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
267
+ console.log("PUBLIC URL:");
268
+ console.log(url);
269
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
270
+ console.log("Share this URL with anyone!\n");
283
271
  }
284
272
  }
285
273
  // Show other important messages (but filter out most INF/WRN logs)
@@ -289,18 +277,10 @@ function setupTunnelHandlers(serviceName) {
289
277
  } else if (serviceName === "Ngrok") {
290
278
  if (trimmed.includes("https://") || trimmed.includes("http://")) {
291
279
  const url = trimmed;
292
- const minWidth = 60;
293
- const urlLength = url.length + 4;
294
- const boxWidth = Math.max(minWidth, urlLength);
295
-
296
- console.log("\nā•”" + "═".repeat(boxWidth) + "ā•—");
297
- const headerText = "āœ… PUBLIC URL";
298
- const headerPadding = boxWidth - headerText.length;
299
- console.log("ā•‘ " + headerText + " ".repeat(Math.max(0, headerPadding)) + "ā•‘");
300
- console.log("ā• " + "═".repeat(boxWidth) + "ā•£");
301
- const urlPadding = boxWidth - url.length;
302
- console.log("ā•‘ " + url + " ".repeat(Math.max(0, urlPadding)) + "ā•‘");
303
- console.log("ā•š" + "═".repeat(boxWidth) + "ā•\n");
280
+ console.log("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
281
+ console.log("PUBLIC URL:");
282
+ console.log(url);
283
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
304
284
  }
305
285
  } else {
306
286
  // LocalTunnel or other services
@@ -308,18 +288,10 @@ function setupTunnelHandlers(serviceName) {
308
288
  const urlMatch = trimmed.match(/https?:\/\/[^\s]+/);
309
289
  if (urlMatch) {
310
290
  const url = urlMatch[0];
311
- const minWidth = 60;
312
- const urlLength = url.length + 4;
313
- const boxWidth = Math.max(minWidth, urlLength);
314
-
315
- console.log("\nā•”" + "═".repeat(boxWidth) + "ā•—");
316
- const headerText = "āœ… PUBLIC URL";
317
- const headerPadding = boxWidth - headerText.length;
318
- console.log("ā•‘ " + headerText + " ".repeat(Math.max(0, headerPadding)) + "ā•‘");
319
- console.log("ā• " + "═".repeat(boxWidth) + "ā•£");
320
- const urlPadding = boxWidth - url.length;
321
- console.log("ā•‘ " + url + " ".repeat(Math.max(0, urlPadding)) + "ā•‘");
322
- console.log("ā•š" + "═".repeat(boxWidth) + "ā•\n");
291
+ console.log("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
292
+ console.log("PUBLIC URL:");
293
+ console.log(url);
294
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
323
295
  }
324
296
  }
325
297
  }
@@ -334,18 +306,11 @@ function setupTunnelHandlers(serviceName) {
334
306
  const urlMatch = output.match(/(https?:\/\/[^\s]+trycloudflare\.com[^\s]*)/);
335
307
  if (urlMatch) {
336
308
  const url = urlMatch[1];
337
- const minWidth = 60;
338
- const urlLength = url.length + 4;
339
- const boxWidth = Math.max(minWidth, urlLength);
340
-
341
- console.log("\nā•”" + "═".repeat(boxWidth) + "ā•—");
342
- const headerText = "āœ… PUBLIC URL";
343
- const headerPadding = boxWidth - headerText.length;
344
- console.log("ā•‘ " + headerText + " ".repeat(Math.max(0, headerPadding)) + "ā•‘");
345
- console.log("ā• " + "═".repeat(boxWidth) + "ā•£");
346
- const urlPadding = boxWidth - url.length;
347
- console.log("ā•‘ " + url + " ".repeat(Math.max(0, urlPadding)) + "ā•‘");
348
- console.log("ā•š" + "═".repeat(boxWidth) + "ā•\n");
309
+ console.log("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
310
+ console.log("PUBLIC URL:");
311
+ console.log(url);
312
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
313
+ console.log("Share this URL with anyone!\n");
349
314
  }
350
315
  }
351
316
 
@@ -353,25 +318,25 @@ function setupTunnelHandlers(serviceName) {
353
318
  if (!output.includes("INF") && !output.includes("WRN")) {
354
319
  const trimmed = output.trim();
355
320
  if (trimmed && !trimmed.includes("originCertPath")) {
356
- console.error(`āš ļø ${trimmed}`);
321
+ console.error(`Error: ${trimmed}`);
357
322
  }
358
323
  }
359
324
  });
360
325
 
361
326
  tunnelProcess.on("error", (error) => {
362
- console.error(`\nāŒ ${serviceName} error:`, error.message);
327
+ console.error(`\n${serviceName} error:`, error.message);
363
328
  });
364
329
 
365
330
  tunnelProcess.on("exit", (code) => {
366
331
  if (code !== 0 && code !== null) {
367
- console.error(`\nāš ļø ${serviceName} exited with code ${code}`);
332
+ console.error(`\n${serviceName} exited with code ${code}`);
368
333
  }
369
334
  });
370
335
  }
371
336
 
372
337
  // Handle cleanup on exit
373
338
  function cleanup() {
374
- console.log("\n\nšŸ›‘ Shutting down tunnel...");
339
+ console.log("\nShutting down tunnel...");
375
340
  try {
376
341
  if (tunnelProcess) {
377
342
  tunnelProcess.kill();
@@ -21,7 +21,7 @@ const proxy = httpProxy.createProxyServer({
21
21
 
22
22
  // Handle proxy errors
23
23
  proxy.on("error", (err, req, res) => {
24
- console.error("āŒ Proxy error:", err.message);
24
+ console.error("Proxy error:", err.message);
25
25
  if (res.writeHead) {
26
26
  res.writeHead(502, { "Content-Type": "text/plain" });
27
27
  res.end("Bad Gateway: Could not connect to your dev server.\nMake sure it's running on port " + TARGET_PORT);
@@ -52,21 +52,19 @@ server.on("upgrade", (req, socket, head) => {
52
52
 
53
53
  // Start server
54
54
  server.listen(PROXY_PORT, () => {
55
- console.log("╔════════════════════════════════════════════╗");
56
- console.log("ā•‘ šŸ”— DevTunnel Proxy Server ā•‘");
57
- console.log("╠════════════════════════════════════════════╣");
58
- console.log(`ā•‘ šŸ“¦ Project: ${PROJECT_NAME.padEnd(28)} ā•‘`);
59
- console.log(`ā•‘ šŸŽÆ Dev Server: http://localhost:${TARGET_PORT.toString().padEnd(7)} ā•‘`);
60
- console.log(`ā•‘ šŸ”Œ Proxy Port: ${PROXY_PORT.toString().padEnd(28)} ā•‘`);
61
- console.log("╠════════════════════════════════════════════╣");
62
- console.log("ā•‘ āœ… Ready! Tunnel will connect to proxy ā•‘");
63
- console.log("ā•‘ šŸ’” No config changes needed ā•‘");
64
- console.log("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•\n");
55
+ console.log("DevTunnel Proxy Server");
56
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
57
+ console.log(`Project: ${PROJECT_NAME}`);
58
+ console.log(`Dev Server: http://localhost:${TARGET_PORT}`);
59
+ console.log(`Proxy Port: ${PROXY_PORT}`);
60
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
61
+ console.log("Ready! Tunnel will connect to proxy");
62
+ console.log("No config changes needed\n");
65
63
  });
66
64
 
67
65
  // Handle shutdown
68
66
  process.on("SIGINT", () => {
69
- console.log("\n\nšŸ›‘ Shutting down proxy...");
67
+ console.log("\nShutting down proxy...");
70
68
  server.close();
71
69
  process.exit(0);
72
70
  });
package/src/core/start.js CHANGED
@@ -38,22 +38,22 @@ async function commandExists(command) {
38
38
  // Main function
39
39
  async function main() {
40
40
  console.clear();
41
- console.log("\n╔════════════════════════════════════════════╗");
42
- console.log("ā•‘ ā•‘");
43
- console.log("ā•‘ šŸš€ DevTunnel v3.0 ā•‘");
44
- console.log("ā•‘ ā•‘");
45
- console.log("ā•‘ Share local servers worldwide ā•‘");
46
- console.log("ā•‘ ā•‘");
47
- console.log("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•\n");
41
+ console.log("DevTunnel v3.0.1");
42
+ console.log("Share your local dev servers worldwide");
43
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
44
+ console.log("Developer: maiz");
45
+ console.log("Repository: https://github.com/maiz-an/DevTunnel");
46
+ console.log("Website: https://devtunnel.vercel.app");
47
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
48
48
 
49
49
  // Step 1: Check Node.js
50
50
  console.log("[1/4] Checking Node.js...");
51
51
  if (!await commandExists("node")) {
52
- console.log("āŒ ERROR: Node.js not found!");
52
+ console.log("ERROR: Node.js not found!");
53
53
  console.log("Install from: https://nodejs.org/");
54
54
  process.exit(1);
55
55
  }
56
- console.log("āœ… SUCCESS: Node.js installed\n");
56
+ console.log("SUCCESS: Node.js installed\n");
57
57
 
58
58
  // Step 2: Check Cloudflare (bundled or system-installed)
59
59
  console.log("[2/4] Checking Cloudflare...");
@@ -64,37 +64,37 @@ async function main() {
64
64
  let cloudflareAvailable = false;
65
65
 
66
66
  if (hasBundledCloudflared()) {
67
- console.log("āœ… SUCCESS: Using bundled Cloudflare (no install needed)");
67
+ console.log("SUCCESS: Using bundled Cloudflare (no install needed)");
68
68
  cloudflareAvailable = true;
69
69
  } else if (await commandExists("cloudflared")) {
70
- console.log("āœ… SUCCESS: Cloudflare installed on system");
70
+ console.log("SUCCESS: Cloudflare installed on system");
71
71
  cloudflareAvailable = true;
72
72
  } else {
73
- console.log("šŸ“¦ First time setup - Downloading Cloudflare...");
74
- console.log("šŸ’” This only happens once (~40MB, 10-30 seconds)\n");
73
+ console.log("First time setup - Downloading Cloudflare...");
74
+ console.log("This only happens once (~40MB, 10-30 seconds)\n");
75
75
 
76
76
  try {
77
77
  const bundledPath = await setupCloudflared();
78
78
 
79
79
  if (bundledPath) {
80
- console.log("āœ… SUCCESS: Cloudflare ready to use");
80
+ console.log("SUCCESS: Cloudflare ready to use");
81
81
  cloudflareAvailable = true;
82
82
  } else {
83
- console.log("āš ļø Could not download Cloudflare");
84
- console.log("šŸ”„ Will use alternative tunnel services\n");
83
+ console.log("Could not download Cloudflare");
84
+ console.log("Will use alternative tunnel services\n");
85
85
  }
86
86
  } catch (err) {
87
- console.log(`āš ļø Setup error: ${err.message}`);
88
- console.log("šŸ”„ Will use alternative tunnel services\n");
87
+ console.log(`Setup error: ${err.message}`);
88
+ console.log("Will use alternative tunnel services\n");
89
89
  }
90
90
  }
91
91
 
92
92
  // Show what's available
93
93
  if (!cloudflareAvailable) {
94
- console.log("šŸ’” DevTunnel has multi-service fallback:");
95
- console.log(" → Cloudflare (fastest, no password)");
96
- console.log(" → Ngrok (fast alternative)");
97
- console.log(" → LocalTunnel (backup option)");
94
+ console.log("DevTunnel has multi-service fallback:");
95
+ console.log(" Cloudflare (fastest, no password)");
96
+ console.log(" Ngrok (fast alternative)");
97
+ console.log(" LocalTunnel (backup option)");
98
98
  console.log("");
99
99
  }
100
100
 
@@ -102,32 +102,32 @@ async function main() {
102
102
  console.log("[3/4] Checking dependencies...");
103
103
  const nodeModulesPath = join(PROJECT_ROOT, "node_modules");
104
104
  if (!existsSync(nodeModulesPath)) {
105
- console.log("šŸ“¦ Installing dependencies...\n");
105
+ console.log("Installing dependencies...\n");
106
106
  // Run npm install in the project root directory
107
107
  const result = await runCommand("npm", ["install"], PROJECT_ROOT);
108
108
  if (result.code !== 0) {
109
- console.log("\nāŒ ERROR: npm install failed");
109
+ console.log("\nERROR: npm install failed");
110
110
  process.exit(1);
111
111
  }
112
- console.log("\nāœ… SUCCESS: Dependencies installed");
112
+ console.log("\nSUCCESS: Dependencies installed");
113
113
  } else {
114
- console.log("āœ… SUCCESS: Dependencies already installed");
114
+ console.log("SUCCESS: Dependencies already installed");
115
115
  }
116
116
  console.log("");
117
117
 
118
118
  // Step 4: Select folder using native OS dialog
119
119
  console.log("[4/4] Select your project folder...");
120
- console.log("ā³ Opening folder picker...\n");
120
+ console.log("Opening folder picker...\n");
121
121
 
122
122
  const projectPath = await selectFolder();
123
123
 
124
124
  if (!projectPath || projectPath.length === 0) {
125
- console.log("āŒ ERROR: No folder selected");
125
+ console.log("ERROR: No folder selected");
126
126
  process.exit(1);
127
127
  }
128
128
 
129
129
  const projectName = basename(projectPath);
130
- console.log(`āœ… Selected: ${projectPath}\n`);
130
+ console.log(`Selected: ${projectPath}\n`);
131
131
 
132
132
  // Get port
133
133
  const portResponse = await prompts({
@@ -138,23 +138,22 @@ async function main() {
138
138
  });
139
139
 
140
140
  if (!portResponse.port) {
141
- console.log("āŒ ERROR: No port entered");
141
+ console.log("ERROR: No port entered");
142
142
  process.exit(1);
143
143
  }
144
144
 
145
145
  const devPort = portResponse.port;
146
146
  const proxyPort = devPort + 1000; // Use port 1000 higher for proxy
147
147
 
148
- console.log("\n╔════════════════════════════════════════════╗");
149
- console.log("ā•‘ šŸ”§ Configuration ā•‘");
150
- console.log("╠════════════════════════════════════════════╣");
151
- console.log(`ā•‘ šŸ“¦ Project: ${projectName.padEnd(28)} ā•‘`);
152
- console.log(`ā•‘ šŸŽÆ Dev Server: localhost:${devPort.toString().padEnd(17)} ā•‘`);
153
- console.log(`ā•‘ šŸ”Œ Proxy Port: ${proxyPort.toString().padEnd(28)} ā•‘`);
154
- console.log("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•\n");
148
+ console.log("\nConfiguration:");
149
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
150
+ console.log(`Project: ${projectName}`);
151
+ console.log(`Dev Server: localhost:${devPort}`);
152
+ console.log(`Proxy Port: ${proxyPort}`);
153
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
155
154
 
156
155
  // Start proxy server
157
- console.log("⚔ Starting services...\n");
156
+ console.log("Starting services...\n");
158
157
  const proxyPath = join(__dirname, "proxy-server.js");
159
158
  const proxyProcess = spawn("node", [proxyPath, devPort.toString(), proxyPort.toString(), projectName], {
160
159
  stdio: "inherit",
@@ -174,7 +173,7 @@ async function main() {
174
173
 
175
174
  // Handle cleanup
176
175
  const cleanup = () => {
177
- console.log("\nšŸ›‘ Shutting down...");
176
+ console.log("\nShutting down...");
178
177
  proxyProcess.kill();
179
178
  tunnelProcess.kill();
180
179
  process.exit(0);
@@ -195,6 +194,6 @@ async function main() {
195
194
 
196
195
  // Run
197
196
  main().catch((error) => {
198
- console.error("\nāŒ ERROR:", error.message);
197
+ console.error("\nERROR:", error.message);
199
198
  process.exit(1);
200
199
  });