





























@@ -14,6 +14,26 @@ interface Options {
1414skipTelegram: boolean;
1515}
161617+export type RunOptions = {
18+capture?: boolean;
19+timeoutMs?: number;
20+};
21+22+export type WorkflowRunInfo = {
23+conclusion: string | null;
24+html_url: string;
25+status: string;
26+updated_at: string;
27+};
28+29+export type PollRunOptions = {
30+pollIntervalMs?: number;
31+readRun?: (repo: string, runId: string) => WorkflowRunInfo;
32+sleep?: (ms: number) => Promise<void>;
33+timeoutMs?: number;
34+now?: () => number;
35+};
36+1737function usage(): string {
1838return `Usage: pnpm release:beta-smoke -- --beta beta4 [options]
1939@@ -88,15 +108,43 @@ function requireValue(argv: string[], index: number, flag: string): string {
88108}
8910990110const CAPTURE_MAX_BUFFER_BYTES = 32 * 1024 * 1024;
111+const DEFAULT_COMMAND_TIMEOUT_MS = readPositiveInt(
112+process.env.OPENCLAW_RELEASE_BETA_SMOKE_COMMAND_MS,
113+10 * 60_000,
114+);
115+const TELEGRAM_POLL_INTERVAL_MS = readPositiveInt(
116+process.env.OPENCLAW_RELEASE_BETA_SMOKE_POLL_INTERVAL_MS,
117+30_000,
118+);
119+const TELEGRAM_POLL_TIMEOUT_MS = readPositiveInt(
120+process.env.OPENCLAW_RELEASE_BETA_SMOKE_POLL_TIMEOUT_MS,
121+4 * 60 * 60_000,
122+);
123+124+function readPositiveInt(raw: string | undefined, fallback: number): number {
125+const text = (raw ?? "").trim();
126+if (!/^\d+$/u.test(text)) {
127+return fallback;
128+}
129+const parsed = Number(text);
130+return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
131+}
9113292-function run(command: string, args: string[], input?: { capture?: boolean }): string {
133+export function run(command: string, args: string[], input?: RunOptions): string {
134+const timeoutMs = input?.timeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS;
93135const result = spawnSync(command, args, {
94136encoding: "utf8",
137+killSignal: "SIGKILL",
95138maxBuffer: CAPTURE_MAX_BUFFER_BYTES,
96139stdio: input?.capture ? ["ignore", "pipe", "pipe"] : "inherit",
140+timeout: timeoutMs,
97141});
98-if (result.status !== 0) {
99-const reason = result.status ?? result.signal ?? result.error?.message ?? "unknown";
142+if (result.error || result.status !== 0) {
143+const errorCode = (result.error as NodeJS.ErrnoException | undefined)?.code;
144+const reason =
145+errorCode === "ETIMEDOUT"
146+ ? `timed out after ${timeoutMs}ms`
147+ : (result.status ?? result.signal ?? result.error?.message ?? "unknown");
100148const stderr = result.stderr ? `\n${result.stderr}` : "";
101149throw new Error(`${command} ${args.join(" ")} failed with ${reason}${stderr}`);
102150}
@@ -161,7 +209,7 @@ function runParallels(beta: string, model: string): void {
161209"150m",
162210 ...forwarded.map(shellQuote),
163211].join(" ");
164-run("bash", ["-lc", command]);
212+run("bash", ["-lc", command], { timeoutMs: 155 * 60_000 });
165213}
166214167215function ghJson(repo: string, pathSuffix: string): unknown {
@@ -268,14 +316,22 @@ async function dispatchTelegram(options: Options, packageSpec: string): Promise<
268316});
269317}
270318271-async function pollRun(repo: string, runId: string): Promise<void> {
319+export async function pollRun(
320+repo: string,
321+runId: string,
322+options: PollRunOptions = {},
323+): Promise<void> {
324+const started = (options.now ?? Date.now)();
325+const timeoutMs = Math.max(1, options.timeoutMs ?? TELEGRAM_POLL_TIMEOUT_MS);
326+const pollIntervalMs = Math.max(1, options.pollIntervalMs ?? TELEGRAM_POLL_INTERVAL_MS);
327+const sleep =
328+options.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));
329+const readRun =
330+options.readRun ??
331+((currentRepo: string, currentRunId: string) =>
332+ghJson(currentRepo, `actions/runs/${currentRunId}`) as WorkflowRunInfo);
272333for (;;) {
273-const info = ghJson(repo, `actions/runs/${runId}`) as {
274-conclusion: string | null;
275-html_url: string;
276-status: string;
277-updated_at: string;
278-};
334+const info = readRun(repo, runId);
279335console.log(
280336`Telegram workflow ${runId}: ${info.status}${info.conclusion ? `/${info.conclusion}` : ""} updated=${info.updated_at}`,
281337);
@@ -288,7 +344,11 @@ async function pollRun(repo: string, runId: string): Promise<void> {
288344console.log(info.html_url);
289345return;
290346}
291-await new Promise((resolve) => setTimeout(resolve, 30_000));
347+const elapsedMs = (options.now ?? Date.now)() - started;
348+if (elapsedMs >= timeoutMs) {
349+throw new Error(`Telegram workflow ${runId} did not complete within ${timeoutMs}ms`);
350+}
351+await sleep(Math.min(pollIntervalMs, timeoutMs - elapsedMs));
292352}
293353}
294354此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。