| 77 | |
| 78 | /** Resolve once a TCP connect to localhost:port succeeds (SSH bound the forward). */ |
| 79 | const waitLocalPort = async (port: number, attempts = 40): Promise<void> => { |
| 80 | for (let i = 0; i < attempts; i++) { |
| 81 | const ok = await new Promise<boolean>((resolve) => { |
| 82 | const sock = net.connect({ host: "127.0.0.1", port }, () => { |
| 83 | sock.destroy(); |
| 84 | resolve(true); |
| 85 | }); |
| 86 | sock.on("error", () => resolve(false)); |
| 87 | sock.setTimeout(1000, () => { |
| 88 | sock.destroy(); |
| 89 | resolve(false); |
| 90 | }); |
| 91 | }); |
| 92 | if (ok) return; |
| 93 | await sleep(500); |
| 94 | } |
| 95 | throw new Error(`tunnel local port ${port} never came up`); |
| 96 | }; |
| 97 | |
| 98 | export const tartVm = (os: "macos" | "linux", arch: VmArch = "arm64"): VmProvider => ({ |
| 99 | os, |