fix: combine gateway start + port wait into single SSH session (#1642)

The old flow opened up to 60+ separate fly ssh console sessions to
poll port 18789 after starting the gateway daemon. Each session opens
a new WireGuard tunnel which is slow and flaky.

Now: one SSH session starts the daemon, then polls the port in-band
with a simple for loop. Output from the loop also serves as a
keepalive for flyctl.

Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
A 2026-02-21 16:16:08 -08:00 committed by GitHub
parent a2dfddec3d
commit b43d3f1b70
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 7 additions and 30 deletions

View file

@ -1,6 +1,6 @@
{ {
"name": "@openrouter/spawn", "name": "@openrouter/spawn",
"version": "0.5.28", "version": "0.5.29",
"type": "module", "type": "module",
"bin": { "bin": {
"spawn": "cli.js" "spawn": "cli.js"

View file

@ -13,7 +13,6 @@ import {
} from "./ui"; } from "./ui";
import { import {
runServer, runServer,
runServerCapture,
uploadFile, uploadFile,
runWithRetry, runWithRetry,
} from "./fly"; } from "./fly";
@ -277,33 +276,14 @@ async function setupOpenclawConfig(
await uploadConfigFile(config, "$HOME/.openclaw/openclaw.json"); await uploadConfigFile(config, "$HOME/.openclaw/openclaw.json");
} }
async function startOpenclawGateway(): Promise<void> { async function startGateway(): Promise<void> {
logStep("Starting OpenClaw gateway daemon..."); logStep("Starting OpenClaw gateway daemon...");
await runServer( await runServer(
"source ~/.spawnrc 2>/dev/null; export PATH=$(npm prefix -g 2>/dev/null)/bin:$HOME/.bun/bin:$HOME/.local/bin:$PATH; if command -v setsid >/dev/null 2>&1; then setsid openclaw gateway > /tmp/openclaw-gateway.log 2>&1 < /dev/null & else nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 < /dev/null & fi", `source ~/.spawnrc 2>/dev/null; export PATH=$(npm prefix -g 2>/dev/null)/bin:$HOME/.bun/bin:$HOME/.local/bin:$PATH; ` +
`if command -v setsid >/dev/null 2>&1; then setsid openclaw gateway > /tmp/openclaw-gateway.log 2>&1 < /dev/null & ` +
`else nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 < /dev/null & fi`,
); );
} logInfo("OpenClaw gateway started");
async function waitForOpenclawGateway(): Promise<void> {
logStep("Waiting for OpenClaw gateway to start...");
const maxWait = 60;
for (let elapsed = 0; elapsed < maxWait; elapsed++) {
try {
await runServerCapture(
`nc -z 127.0.0.1 18789 2>/dev/null || (command -v telnet >/dev/null && timeout 1 telnet 127.0.0.1 18789 2>&1 | grep -q Connected)`,
5,
);
logInfo(`Gateway ready after ${elapsed}s`);
return;
} catch { /* not ready */ }
await new Promise((r) => setTimeout(r, 1000));
}
logError(`OpenClaw gateway failed to start after ${maxWait}s`);
logInfo("Check gateway logs: cat /tmp/openclaw-gateway.log");
try {
await runServer("tail -10 /tmp/openclaw-gateway.log 2>/dev/null || true");
} catch { /* ignore */ }
throw new Error("OpenClaw gateway timeout");
} }
// ─── OpenCode Install Command ──────────────────────────────────────────────── // ─── OpenCode Install Command ────────────────────────────────────────────────
@ -358,10 +338,7 @@ export const agents: Record<string, AgentConfig> = {
], ],
configure: (apiKey, modelId) => configure: (apiKey, modelId) =>
setupOpenclawConfig(apiKey, modelId || "openrouter/auto"), setupOpenclawConfig(apiKey, modelId || "openrouter/auto"),
preLaunch: async () => { preLaunch: startGateway,
await startOpenclawGateway();
await waitForOpenclawGateway();
},
launchCmd: () => launchCmd: () =>
"source ~/.spawnrc 2>/dev/null; source ~/.zshrc 2>/dev/null; openclaw tui", "source ~/.spawnrc 2>/dev/null; source ~/.zshrc 2>/dev/null; openclaw tui",
}, },