kiro-mobile-bridge 1.0.13 → 1.0.14

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": "kiro-mobile-bridge",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "A simple mobile web interface for monitoring Kiro IDE agent sessions from your phone over LAN",
5
5
  "type": "module",
6
6
  "main": "src/server.js",
@@ -7,13 +7,27 @@ import { CDP_CALL_TIMEOUT, HTTP_TIMEOUT } from '../utils/constants.js';
7
7
 
8
8
  /**
9
9
  * Fetch JSON from a CDP endpoint
10
+ * Tries both 127.0.0.1 and localhost for cross-platform compatibility
10
11
  * @param {number} port - The port to fetch from
11
12
  * @param {string} path - The path to fetch (default: /json/list)
12
13
  * @returns {Promise<any>} - Parsed JSON response
13
14
  */
14
15
  export function fetchCDPTargets(port, path = '/json/list') {
16
+ // Try 127.0.0.1 first, then localhost as fallback
17
+ return fetchFromHost('127.0.0.1', port, path)
18
+ .catch(() => fetchFromHost('localhost', port, path));
19
+ }
20
+
21
+ /**
22
+ * Fetch JSON from a specific host
23
+ * @param {string} host - The host to connect to
24
+ * @param {number} port - The port to fetch from
25
+ * @param {string} path - The path to fetch
26
+ * @returns {Promise<any>} - Parsed JSON response
27
+ */
28
+ function fetchFromHost(host, port, path) {
15
29
  return new Promise((resolve, reject) => {
16
- const url = `http://127.0.0.1:${port}${path}`;
30
+ const url = `http://${host}:${port}${path}`;
17
31
 
18
32
  const req = http.get(url, { timeout: HTTP_TIMEOUT }, (res) => {
19
33
  let data = '';
@@ -1,11 +1,19 @@
1
1
  /**
2
- * Network utilities
2
+ * Network utilities for cross-platform local IP detection
3
+ *
4
+ * Supports: Windows, macOS, Linux
5
+ *
6
+ * Node.js os.networkInterfaces() family property:
7
+ * - Node < 18.0.0: returns string ('IPv4' or 'IPv6')
8
+ * - Node 18.0.0 - 18.3.x: returns number (4 or 6)
9
+ * - Node >= 18.4.0: returns string ('IPv4' or 'IPv6')
3
10
  */
4
11
  import { networkInterfaces } from 'os';
5
12
 
6
13
  /**
7
14
  * Check if interface is IPv4
8
15
  * Handles both string ('IPv4') and number (4) family values
16
+ * for compatibility across Node.js versions
9
17
  * @param {object} iface - Network interface object
10
18
  * @returns {boolean}
11
19
  */
@@ -13,22 +21,66 @@ function isIPv4(iface) {
13
21
  return iface.family === 'IPv4' || iface.family === 4;
14
22
  }
15
23
 
24
+ /**
25
+ * Check if interface name is a virtual/container interface to skip
26
+ * @param {string} name - Interface name
27
+ * @returns {boolean}
28
+ */
29
+ function isVirtualInterface(name) {
30
+ const lowerName = name.toLowerCase();
31
+ const virtualPatterns = [
32
+ 'vethernet', // Windows WSL/Hyper-V
33
+ 'docker', // Docker
34
+ 'vmware', // VMware
35
+ 'virtualbox', // VirtualBox
36
+ 'vbox', // VirtualBox alternate
37
+ 'virbr', // Linux libvirt bridge
38
+ 'br-', // Docker bridge
39
+ 'veth', // Virtual ethernet
40
+ 'tailscale', // Tailscale VPN
41
+ 'tun', // VPN tunnel
42
+ 'tap', // VPN tap
43
+ 'utun', // macOS VPN
44
+ 'awdl', // Apple Wireless Direct Link
45
+ 'llw', // Apple Low Latency WLAN
46
+ 'bridge', // Bridge interfaces
47
+ 'ham', // Hamachi VPN
48
+ 'zt', // ZeroTier
49
+ ];
50
+
51
+ return virtualPatterns.some(pattern => lowerName.includes(pattern));
52
+ }
53
+
16
54
  /**
17
55
  * Get local IP address for LAN access
18
- * Returns the first non-internal IPv4 address found.
56
+ * Returns the first non-internal IPv4 address found, prioritizing
57
+ * physical network interfaces over virtual ones.
19
58
  *
20
- * NOTE: On systems with multiple network interfaces, this returns the first one found.
21
- * For more control, consider using environment variables or configuration.
59
+ * Platform-specific interface names:
60
+ * - Windows: 'Ethernet', 'Wi-Fi', 'Ethernet 2', 'Local Area Connection'
61
+ * - macOS: 'en0' (Wi-Fi), 'en1' (Ethernet), 'en2', etc.
62
+ * - Linux: 'eth0', 'enp0s3', 'ens33', 'wlan0', 'wlp2s0'
22
63
  *
23
64
  * @returns {string} - Local IP or 'localhost' if no suitable interface found
24
65
  */
25
66
  export function getLocalIP() {
26
67
  const interfaces = networkInterfaces();
27
68
 
28
- // Prioritize common interface names (Linux, macOS, Windows)
29
- const priorityInterfaces = ['Ethernet', 'Wi-Fi', 'eth0', 'en0', 'wlan0'];
69
+ // Priority 1: Common physical interface names across platforms
70
+ // Order matters - check most common first
71
+ const priorityInterfaces = [
72
+ // Windows
73
+ 'Ethernet', 'Wi-Fi', 'Ethernet 2', 'Local Area Connection',
74
+ // macOS
75
+ 'en0', 'en1', 'en2', 'en3', 'en4', 'en5',
76
+ // Linux (traditional)
77
+ 'eth0', 'eth1', 'wlan0', 'wlan1',
78
+ // Linux (systemd predictable names)
79
+ 'enp0s3', 'enp0s25', 'enp0s31f6', 'ens33', 'ens160', 'ens192',
80
+ 'wlp2s0', 'wlp3s0', 'wlp0s20f3',
81
+ ];
30
82
 
31
- // First, try priority interfaces
83
+ // First pass: try priority interfaces
32
84
  for (const name of priorityInterfaces) {
33
85
  const ifaces = interfaces[name];
34
86
  if (ifaces) {
@@ -40,15 +92,10 @@ export function getLocalIP() {
40
92
  }
41
93
  }
42
94
 
43
- // Fallback: return first non-internal IPv4 (skip virtual/WSL interfaces)
95
+ // Second pass: any non-virtual interface
44
96
  for (const name of Object.keys(interfaces)) {
45
- // Skip virtual interfaces (WSL, Docker, VPN, etc.)
46
- if (name.toLowerCase().includes('vethernet') ||
47
- name.toLowerCase().includes('docker') ||
48
- name.toLowerCase().includes('vmware') ||
49
- name.toLowerCase().includes('virtualbox')) {
50
- continue;
51
- }
97
+ if (isVirtualInterface(name)) continue;
98
+
52
99
  for (const iface of interfaces[name]) {
53
100
  if (isIPv4(iface) && !iface.internal) {
54
101
  return iface.address;
@@ -56,7 +103,7 @@ export function getLocalIP() {
56
103
  }
57
104
  }
58
105
 
59
- // Last resort: any non-internal IPv4
106
+ // Last resort: any non-internal IPv4 (including virtual)
60
107
  for (const name of Object.keys(interfaces)) {
61
108
  for (const iface of interfaces[name]) {
62
109
  if (isIPv4(iface) && !iface.internal) {