@seflless/ghosttown 1.6.0 → 1.6.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seflless/ghosttown",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "description": "Web-based terminal emulator using Ghostty's VT100 parser via WebAssembly",
5
5
  "type": "module",
6
6
  "main": "./dist/ghostty-web.umd.cjs",
package/src/cli.js CHANGED
@@ -512,8 +512,8 @@ function getNextDisplayNumber() {
512
512
  }
513
513
 
514
514
  /**
515
- * Check if the background server is running and get its port
516
- * @returns {{ running: boolean, port: number | null }}
515
+ * Check if the background server is running and get its port and protocol
516
+ * @returns {{ running: boolean, port: number | null, useHttp: boolean }}
517
517
  */
518
518
  function getServerStatus() {
519
519
  try {
@@ -525,22 +525,42 @@ function getServerStatus() {
525
525
  const isRunning = output.split('\n').includes(SERVER_SESSION_NAME);
526
526
 
527
527
  if (!isRunning) {
528
- return { running: false, port: null };
528
+ return { running: false, port: null, useHttp: false };
529
529
  }
530
530
 
531
531
  // Get the port from tmux environment
532
+ let port = 8080;
532
533
  try {
533
534
  const envOutput = execSync(`tmux show-environment -t ${SERVER_SESSION_NAME} GHOSTTOWN_PORT`, {
534
535
  encoding: 'utf8',
535
536
  stdio: ['pipe', 'pipe', 'pipe'],
536
537
  });
537
- const port = Number.parseInt(envOutput.split('=')[1], 10);
538
- return { running: true, port: Number.isNaN(port) ? 8080 : port };
538
+ const parsedPort = Number.parseInt(envOutput.split('=')[1], 10);
539
+ if (!Number.isNaN(parsedPort)) {
540
+ port = parsedPort;
541
+ }
539
542
  } catch (e) {
540
- return { running: true, port: 8080 }; // Default port
543
+ // Use default port
541
544
  }
545
+
546
+ // Get the protocol from tmux environment (default to HTTPS if not set)
547
+ let useHttp = false;
548
+ try {
549
+ const envOutput = execSync(
550
+ `tmux show-environment -t ${SERVER_SESSION_NAME} GHOSTTOWN_USE_HTTP`,
551
+ {
552
+ encoding: 'utf8',
553
+ stdio: ['pipe', 'pipe', 'pipe'],
554
+ }
555
+ );
556
+ useHttp = envOutput.split('=')[1]?.trim() === '1';
557
+ } catch (e) {
558
+ // Use default (HTTPS)
559
+ }
560
+
561
+ return { running: true, port, useHttp };
542
562
  } catch (err) {
543
- return { running: false, port: null };
563
+ return { running: false, port: null, useHttp: false };
544
564
  }
545
565
  }
546
566
 
@@ -1083,8 +1103,9 @@ function killAllSessions() {
1083
1103
  /**
1084
1104
  * Start the server in the background using a tmux session
1085
1105
  * @param {number} port - Port to listen on
1106
+ * @param {boolean} useHttp - Use HTTP instead of HTTPS (default: false, meaning HTTPS is used)
1086
1107
  */
1087
- function startServerInBackground(port = 8080) {
1108
+ function startServerInBackground(port = 8080, useHttp = false) {
1088
1109
  // Check if tmux is installed
1089
1110
  if (!checkTmuxInstalled()) {
1090
1111
  printTmuxInstallHelp();
@@ -1141,24 +1162,34 @@ function startServerInBackground(port = 8080) {
1141
1162
  stdio: 'pipe',
1142
1163
  });
1143
1164
 
1165
+ // Set the protocol environment variable in the tmux session
1166
+ execSync(
1167
+ `tmux set-environment -t ${SERVER_SESSION_NAME} GHOSTTOWN_USE_HTTP ${useHttp ? '1' : '0'}`,
1168
+ {
1169
+ stdio: 'pipe',
1170
+ }
1171
+ );
1172
+
1144
1173
  // Disable status bar for cleaner look
1145
1174
  execSync(`tmux set-option -t ${SERVER_SESSION_NAME} status off`, { stdio: 'pipe' });
1146
1175
 
1147
- // Run the server with background mode flag
1176
+ // Run the server with background mode flag (add --http if needed)
1177
+ const httpFlag = useHttp ? ' --http' : '';
1148
1178
  execSync(
1149
- `tmux send-keys -t ${SERVER_SESSION_NAME} 'node "${gtPath}" --server-background -p ${port}' Enter`,
1179
+ `tmux send-keys -t ${SERVER_SESSION_NAME} 'node "${gtPath}" --server-background -p ${port}${httpFlag}' Enter`,
1150
1180
  { stdio: 'pipe' }
1151
1181
  );
1152
1182
 
1153
1183
  // Get local IPs for display
1154
1184
  const localIPs = getLocalIPs();
1185
+ const protocol = useHttp ? 'http' : 'https';
1155
1186
 
1156
1187
  console.log('');
1157
1188
  console.log(` ${BOLD_YELLOW}Ghosttown server started!${RESET}`);
1158
1189
  console.log('');
1159
- console.log(` ${CYAN}Open:${RESET} ${BEIGE}http://localhost:${port}${RESET}`);
1190
+ console.log(` ${CYAN}Open:${RESET} ${BEIGE}${protocol}://localhost:${port}${RESET}`);
1160
1191
  if (localIPs.length > 0) {
1161
- console.log(` ${CYAN}Network:${RESET} ${BEIGE}http://${localIPs[0]}:${port}${RESET}`);
1192
+ console.log(` ${CYAN}Network:${RESET} ${BEIGE}${protocol}://${localIPs[0]}:${port}${RESET}`);
1162
1193
  }
1163
1194
  console.log('');
1164
1195
  console.log(` ${CYAN}To stop:${RESET} ${BEIGE}gt stop${RESET}`);
@@ -1238,12 +1269,13 @@ function showServerStatus() {
1238
1269
  if (status.running) {
1239
1270
  const localIPs = getLocalIPs();
1240
1271
  const port = status.port || 8080;
1272
+ const protocol = status.useHttp ? 'http' : 'https';
1241
1273
 
1242
1274
  console.log(` ${GREEN}Server is running${RESET}`);
1243
1275
  console.log('');
1244
- console.log(` ${CYAN}Open:${RESET} ${BEIGE}http://localhost:${port}${RESET}`);
1276
+ console.log(` ${CYAN}Open:${RESET} ${BEIGE}${protocol}://localhost:${port}${RESET}`);
1245
1277
  if (localIPs.length > 0) {
1246
- console.log(` ${CYAN}Network:${RESET} ${BEIGE}http://${localIPs[0]}:${port}${RESET}`);
1278
+ console.log(` ${CYAN}Network:${RESET} ${BEIGE}${protocol}://${localIPs[0]}:${port}${RESET}`);
1247
1279
  }
1248
1280
  console.log('');
1249
1281
  console.log(` ${DIM}To stop: gt stop${RESET}`);
@@ -1496,15 +1528,13 @@ Examples:
1496
1528
  Aliases:
1497
1529
  This CLI can also be invoked as 'gt' or 'ght'.
1498
1530
  `);
1499
- handled = true;
1500
- break;
1531
+ process.exit(0);
1501
1532
  }
1502
1533
 
1503
1534
  // Handle version flag
1504
1535
  if (arg === '-v' || arg === '--version') {
1505
1536
  console.log(VERSION);
1506
- handled = true;
1507
- break;
1537
+ process.exit(0);
1508
1538
  }
1509
1539
 
1510
1540
  // Handle list command
@@ -1569,20 +1599,28 @@ Aliases:
1569
1599
 
1570
1600
  // Handle start command
1571
1601
  else if (arg === 'start') {
1572
- // Check for -p flag after 'start'
1602
+ // Parse remaining args after 'start' for -p and --http flags
1573
1603
  let startPort = 8080;
1574
- if (args[i + 1] === '-p' || args[i + 1] === '--port') {
1575
- const portArg = args[i + 2];
1576
- if (portArg) {
1577
- startPort = Number.parseInt(portArg, 10);
1578
- if (Number.isNaN(startPort) || startPort < 1 || startPort > 65535) {
1579
- console.error(`Error: Invalid port number: ${portArg}`);
1580
- process.exit(1);
1604
+ let startUseHttp = false;
1605
+ const remainingArgs = args.slice(i + 1);
1606
+ for (let j = 0; j < remainingArgs.length; j++) {
1607
+ const subArg = remainingArgs[j];
1608
+ if (subArg === '-p' || subArg === '--port') {
1609
+ const portArg = remainingArgs[j + 1];
1610
+ if (portArg) {
1611
+ startPort = Number.parseInt(portArg, 10);
1612
+ if (Number.isNaN(startPort) || startPort < 1 || startPort > 65535) {
1613
+ console.error(`Error: Invalid port number: ${portArg}`);
1614
+ process.exit(1);
1615
+ }
1581
1616
  }
1617
+ j++; // Skip the port value
1618
+ } else if (subArg === '--http') {
1619
+ startUseHttp = true;
1582
1620
  }
1583
1621
  }
1584
1622
  handled = true;
1585
- startServerInBackground(startPort);
1623
+ startServerInBackground(startPort, startUseHttp);
1586
1624
  // startServerInBackground exits, so this won't be reached
1587
1625
  }
1588
1626
 
@@ -0,0 +1,75 @@
1
+ /**
2
+ * CLI tests
3
+ *
4
+ * Tests for the ghosttown CLI command-line interface.
5
+ */
6
+
7
+ import { describe, expect, test } from 'bun:test';
8
+ import { spawn } from 'child_process';
9
+ import { join } from 'path';
10
+ import { fileURLToPath } from 'url';
11
+
12
+ const __dirname = join(fileURLToPath(import.meta.url), '..');
13
+ const CLI_PATH = join(__dirname, '..', 'bin', 'gt.js');
14
+
15
+ /**
16
+ * Run the CLI with given arguments and return stdout/stderr/exit code
17
+ */
18
+ function runCli(args: string[]): Promise<{ stdout: string; stderr: string; code: number }> {
19
+ return new Promise((resolve) => {
20
+ const proc = spawn('node', [CLI_PATH, ...args], {
21
+ stdio: ['pipe', 'pipe', 'pipe'],
22
+ });
23
+
24
+ let stdout = '';
25
+ let stderr = '';
26
+
27
+ proc.stdout.on('data', (data) => {
28
+ stdout += data.toString();
29
+ });
30
+
31
+ proc.stderr.on('data', (data) => {
32
+ stderr += data.toString();
33
+ });
34
+
35
+ proc.on('close', (code) => {
36
+ resolve({ stdout, stderr, code: code ?? 1 });
37
+ });
38
+ });
39
+ }
40
+
41
+ describe('CLI', () => {
42
+ describe('version flag', () => {
43
+ test('-v should print version and exit', async () => {
44
+ const result = await runCli(['-v']);
45
+ expect(result.code).toBe(0);
46
+ expect(result.stdout.trim()).toMatch(/^\d+\.\d+\.\d+$/);
47
+ expect(result.stderr).toBe('');
48
+ });
49
+
50
+ test('--version should print version and exit', async () => {
51
+ const result = await runCli(['--version']);
52
+ expect(result.code).toBe(0);
53
+ expect(result.stdout.trim()).toMatch(/^\d+\.\d+\.\d+$/);
54
+ expect(result.stderr).toBe('');
55
+ });
56
+ });
57
+
58
+ describe('help flag', () => {
59
+ test('-h should print help and exit', async () => {
60
+ const result = await runCli(['-h']);
61
+ expect(result.code).toBe(0);
62
+ expect(result.stdout).toContain('Usage: ghosttown');
63
+ expect(result.stdout).toContain('--version');
64
+ expect(result.stdout).toContain('--help');
65
+ expect(result.stderr).toBe('');
66
+ });
67
+
68
+ test('--help should print help and exit', async () => {
69
+ const result = await runCli(['--help']);
70
+ expect(result.code).toBe(0);
71
+ expect(result.stdout).toContain('Usage: ghosttown');
72
+ expect(result.stderr).toBe('');
73
+ });
74
+ });
75
+ });