













@@ -2,6 +2,7 @@
22import childProcess from "node:child_process";
33import { createHash } from "node:crypto";
44import fs from "node:fs";
5+import net from "node:net";
56import os from "node:os";
67import path from "node:path";
78import process from "node:process";
@@ -30,7 +31,6 @@ const DEFAULT_MAX_COMMAND_RSS_MIB = 8192;
3031const DEFAULT_OUTPUT_CAPTURE_CHARS = 1024 * 1024;
3132const GATEWAY_TEARDOWN_GRACE_MS = 10000;
3233const GATEWAY_TEARDOWN_KILL_GRACE_MS = 2000;
33-const DEFAULT_PORT = 19000 + Math.floor(Math.random() * 1000);
3434const LOG_SCAN_CHUNK_BYTES = 64 * 1024;
3535const LOG_SCAN_MAX_LINE_CHARS = 16 * 1024;
3636const LOG_TAIL_BYTES = 256 * 1024;
@@ -65,12 +65,17 @@ Environment:
6565 OPENCLAW_ENTRY Built OpenClaw entrypoint. Defaults to dist/index.mjs or dist/index.js.
6666 OPENCLAW_KITCHEN_SINK_NPM_SPEC Plugin package spec. Default: npm:@openclaw/kitchen-sink@latest.
6767 OPENCLAW_KITCHEN_SINK_PLUGIN_ID Plugin id. Default: openclaw-kitchen-sink-fixture.
68+ OPENCLAW_KITCHEN_SINK_PERSONALITY Plugin fixture personality. Default: conformance.
69+ OPENCLAW_KITCHEN_SINK_RPC_PORT Gateway loopback port. Default: OS-selected free port.
6870 OPENCLAW_KITCHEN_SINK_RPC_READY_MS Gateway readiness timeout.
6971 OPENCLAW_KITCHEN_SINK_RPC_COMMAND_MS OpenClaw command timeout.
7072 OPENCLAW_KITCHEN_SINK_RPC_INSTALL_MS Plugin install timeout.
7173 OPENCLAW_KITCHEN_SINK_RPC_CALL_MS RPC call timeout.
74+ OPENCLAW_KITCHEN_SINK_RPC_FETCH_MS HTTP readiness probe timeout.
75+ OPENCLAW_KITCHEN_SINK_RPC_FETCH_BODY_BYTES HTTP readiness probe response ceiling.
7276 OPENCLAW_KITCHEN_SINK_MAX_RSS_MIB Gateway RSS ceiling.
7377 OPENCLAW_KITCHEN_SINK_COMMAND_MAX_RSS_MIB Install/CLI command RSS ceiling.
78+ OPENCLAW_KITCHEN_SINK_OUTPUT_CAPTURE_CHARS Per-command stdout/stderr capture ceiling.
7479 OPENCLAW_KITCHEN_SINK_KEEP_TMP=1 Preserve the isolated temp home.
7580`;
7681}
@@ -145,6 +150,42 @@ export function resolveKitchenSinkRpcConfig(env = process.env) {
145150};
146151}
147152153+export async function findAvailableLoopbackPort(options = {}) {
154+const createServer = options.createServer ?? (() => net.createServer());
155+const server = createServer();
156+return await new Promise((resolve, reject) => {
157+const fail = (error) => {
158+server.close?.(() => {});
159+reject(toLintErrorObject(error, "Unable to reserve Kitchen Sink RPC loopback port"));
160+};
161+server.once("error", fail);
162+server.listen(0, "127.0.0.1", () => {
163+server.off?.("error", fail);
164+const address = server.address();
165+const port = typeof address === "object" && address ? address.port : 0;
166+server.close((error) => {
167+if (error) {
168+reject(toLintErrorObject(error, "Unable to close Kitchen Sink RPC loopback port"));
169+return;
170+}
171+if (!Number.isSafeInteger(port) || port <= 0) {
172+reject(new Error(`unable to reserve Kitchen Sink RPC loopback port: ${String(port)}`));
173+return;
174+}
175+resolve(port);
176+});
177+});
178+});
179+}
180+181+export async function resolveKitchenSinkRpcPort(env = process.env, options = {}) {
182+const rawPort = (env.OPENCLAW_KITCHEN_SINK_RPC_PORT || "").trim();
183+if (rawPort) {
184+return readPositiveInt(rawPort, 0, "OPENCLAW_KITCHEN_SINK_RPC_PORT");
185+}
186+return await (options.findAvailablePort ?? findAvailableLoopbackPort)();
187+}
188+148189function resolveOpenClawRunner() {
149190if (process.env.OPENCLAW_ENTRY) {
150191return {
@@ -2200,11 +2241,7 @@ function isNonEmptyString(value) {
22002241export async function main() {
22012242const config = resolveKitchenSinkRpcConfig();
22022243let runner = resolveOpenClawRunner();
2203-const port = readPositiveInt(
2204-process.env.OPENCLAW_KITCHEN_SINK_RPC_PORT,
2205-DEFAULT_PORT,
2206-"OPENCLAW_KITCHEN_SINK_RPC_PORT",
2207-);
2244+const port = await resolveKitchenSinkRpcPort();
22082245const { root, env } = makeEnv();
22092246const logPath = path.join(root, "gateway.log");
22102247const keepTmp = process.env.OPENCLAW_KITCHEN_SINK_KEEP_TMP === "1";
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。