Starts the proxy server and returns its URL. @return the proxy URL (e.g., "http://localhost:12345") @throws IOException if the server fails to start @throws InterruptedException if the startup is interrupted
()
| 79 | * if the startup is interrupted |
| 80 | */ |
| 81 | public String start() throws IOException, InterruptedException { |
| 82 | if (proxyUrl != null) { |
| 83 | return proxyUrl; |
| 84 | } |
| 85 | |
| 86 | // Find the repo root by looking for the test/harness directory |
| 87 | Path harnessDir = findHarnessDirectory(); |
| 88 | if (harnessDir == null) { |
| 89 | throw new IOException("Could not find test/harness directory. " |
| 90 | + "Make sure you are running from within the copilot-sdk repository."); |
| 91 | } |
| 92 | |
| 93 | // Start the harness server using npx tsx |
| 94 | // On Windows, npx is installed as npx.cmd which requires cmd /c to launch |
| 95 | boolean isWindows = System.getProperty("os.name").toLowerCase().contains("win"); |
| 96 | var pb = isWindows |
| 97 | ? new ProcessBuilder("cmd", "/c", "npx", "tsx", "server.ts") |
| 98 | : new ProcessBuilder("npx", "tsx", "server.ts"); |
| 99 | pb.directory(harnessDir.toFile()); |
| 100 | pb.redirectErrorStream(false); |
| 101 | // Tell the replaying proxy to fail fast on unmatched requests rather than |
| 102 | // forwarding them to the real API. Without this, unmatched requests hit the |
| 103 | // live API with a fake token and crash the proxy's JSON parser. |
| 104 | pb.environment().put("GITHUB_ACTIONS", "true"); |
| 105 | |
| 106 | process = pb.start(); |
| 107 | |
| 108 | // Read stdout to get the listening URL |
| 109 | // Note: We keep the reader open to avoid closing the process input stream |
| 110 | stdoutReader = new BufferedReader(new InputStreamReader(process.getInputStream())); |
| 111 | |
| 112 | // Also consume stderr in a background thread to prevent blocking |
| 113 | Thread stderrThread = new Thread(() -> { |
| 114 | try (BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) { |
| 115 | String errLine; |
| 116 | while ((errLine = errReader.readLine()) != null) { |
| 117 | System.err.println("[CapiProxy stderr] " + errLine); |
| 118 | } |
| 119 | } catch (IOException e) { |
| 120 | // Ignore |
| 121 | } |
| 122 | }); |
| 123 | stderrThread.setDaemon(true); |
| 124 | stderrThread.start(); |
| 125 | |
| 126 | String line = stdoutReader.readLine(); |
| 127 | if (line == null) { |
| 128 | // Try to get error info |
| 129 | StringBuilder errInfo = new StringBuilder(); |
| 130 | try (BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) { |
| 131 | String errLine; |
| 132 | while ((errLine = errReader.readLine()) != null) { |
| 133 | errInfo.append(errLine).append("\n"); |
| 134 | } |
| 135 | } |
| 136 | process.destroyForcibly(); |
| 137 | throw new IOException("Failed to read proxy URL - server may have crashed. Stderr: " + errInfo); |
| 138 | } |
no test coverage detected