(workspacePath: string, _startPort: number = DEFAULT_PORT)
| 93 | * @throws Error if no ports available in ±10 range around hash-based port |
| 94 | */ |
| 95 | export async function getFreeHashPort(workspacePath: string, _startPort: number = DEFAULT_PORT): Promise<number> { |
| 96 | // Calculate this workspace's hash-based port |
| 97 | const preferredPort = calculateHashPort(workspacePath); |
| 98 | |
| 99 | // Try preferred port first |
| 100 | if (await isPortAvailable(preferredPort)) { |
| 101 | logger.printInfoLog(`Using workspace-preferred port: ${preferredPort}`); |
| 102 | return preferredPort; |
| 103 | } |
| 104 | |
| 105 | // If preferred port is taken, try nearby ports (±10 range) |
| 106 | // This handles edge case where same workspace runs twice simultaneously |
| 107 | logger.printInfoLog(`Preferred port ${preferredPort} occupied, trying nearby ports...`); |
| 108 | for (let offset = 1; offset <= 10; offset++) { |
| 109 | const portUp = preferredPort + offset; |
| 110 | const portDown = preferredPort - offset; |
| 111 | |
| 112 | if (await isPortAvailable(portUp)) { |
| 113 | logger.printInfoLog(`Using nearby port: ${portUp} (preferred was ${preferredPort})`); |
| 114 | return portUp; |
| 115 | } |
| 116 | if (portDown > 1024 && (await isPortAvailable(portDown))) { |
| 117 | logger.printInfoLog(`Using nearby port: ${portDown} (preferred was ${preferredPort})`); |
| 118 | return portDown; |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | // All ports in ±10 range are occupied |
| 123 | throw new Error(`No available ports found in workspace-preferred range (${preferredPort - 10} to ${preferredPort + 10})`); |
| 124 | } |
| 125 | |
| 126 | async function waitForServerReady(url: string, timeoutMs: number): Promise<boolean> { |
| 127 | const start = Date.now(); |
no test coverage detected