



























@@ -100,6 +100,14 @@ type MantisSlackDesktopSmokeSummary = {
100100slackUrl?: string;
101101startedAt: string;
102102status: "pass" | "fail";
103+warning?: string;
104+};
105+106+type SlackDesktopRemoteMetadata = {
107+gatewayAlive?: boolean;
108+gatewayPid?: string;
109+openedUrl?: string;
110+qaExitCode?: number;
103111};
104112105113const DEFAULT_PROVIDER = "hetzner";
@@ -183,6 +191,31 @@ async function pathExists(filePath: string) {
183191}
184192}
185193194+async function readRemoteMetadata(
195+outputDir: string,
196+): Promise<SlackDesktopRemoteMetadata | undefined> {
197+const metadataPath = path.join(outputDir, "remote-metadata.json");
198+if (!(await pathExists(metadataPath))) {
199+return undefined;
200+}
201+try {
202+const parsed = JSON.parse(await fs.readFile(metadataPath, "utf8")) as unknown;
203+if (!parsed || typeof parsed !== "object") {
204+return undefined;
205+}
206+const candidate = parsed as Record<string, unknown>;
207+return {
208+gatewayAlive:
209+typeof candidate.gatewayAlive === "boolean" ? candidate.gatewayAlive : undefined,
210+gatewayPid: typeof candidate.gatewayPid === "string" ? candidate.gatewayPid : undefined,
211+openedUrl: typeof candidate.openedUrl === "string" ? candidate.openedUrl : undefined,
212+qaExitCode: typeof candidate.qaExitCode === "number" ? candidate.qaExitCode : undefined,
213+};
214+} catch {
215+return undefined;
216+}
217+}
218+186219async function resolveCrabboxBin(params: {
187220env: NodeJS.ProcessEnv;
188221explicit?: string;
@@ -444,7 +477,8 @@ if [ "$setup_gateway" = "1" ]; then
444477 --window-size=1440,1000 \
445478 --window-position=0,0 \
446479 --class=mantis-slack-desktop-smoke \
447- "$slack_url" >"$out/chrome.log" 2>&1 &
480+ "$slack_url" </dev/null >"$out/chrome.log" 2>&1 &
481+ disown "$!" >/dev/null 2>&1 || true
448482else
449483 "$browser_bin" \
450484 --user-data-dir="$profile" \
@@ -496,9 +530,16 @@ qa_status=0
496530MANTIS_SLACK_PATCH
497531 pnpm openclaw config patch --file "$out/slack.socket.patch.json5" --dry-run
498532 pnpm openclaw config patch --file "$out/slack.socket.patch.json5"
499- nohup pnpm openclaw gateway run --dev --allow-unconfigured --port 38973 --cli-backend-logs >"$out/openclaw-gateway.log" 2>&1 &
500- echo "$!" >"$out/openclaw-gateway.pid"
533+ nohup pnpm openclaw gateway run --dev --allow-unconfigured --port 38973 --cli-backend-logs </dev/null >"$out/openclaw-gateway.log" 2>&1 &
534+ gateway_pid="$!"
535+ echo "$gateway_pid" >"$out/openclaw-gateway.pid"
501536 sleep 12
537+ if ! kill -0 "$gateway_pid" >/dev/null 2>&1; then
538+ echo "OpenClaw gateway exited during startup." >&2
539+ wait "$gateway_pid" || true
540+ exit 1
541+ fi
542+ disown "$gateway_pid" >/dev/null 2>&1 || true
502543 else
503544 qa_args=(openclaw qa slack --repo-root . --output-dir "$out/slack-qa" --provider-mode "$provider_mode" --model "$primary_model" --alt-model "$alternate_model" --credential-source "$credential_source" --credential-role "$credential_role")
504545 if [ "$fast_mode" = "1" ]; then
@@ -522,6 +563,8 @@ cat >"$out/remote-metadata.json" <<MANTIS_REMOTE_METADATA
522563 "display": "$DISPLAY",
523564 "openedUrl": "$slack_url",
524565 "gatewaySetup": $setup_gateway,
566+ "gatewayAlive": $(if [ "$setup_gateway" = "1" ] && [ -f "$out/openclaw-gateway.pid" ] && kill -0 "$(cat "$out/openclaw-gateway.pid")" >/dev/null 2>&1; then echo true; else echo false; fi),
567+ "gatewayPid": "$(if [ -f "$out/openclaw-gateway.pid" ]; then cat "$out/openclaw-gateway.pid"; fi)",
525568 "gatewayPort": 38973,
526569 "qaExitCode": $qa_status,
527570 "credentialSource": "$credential_source",
@@ -776,6 +819,7 @@ export async function runMantisSlackDesktopSmoke(
776819let screenshotPath: string | undefined;
777820let slackQaDir: string | undefined;
778821let videoPath: string | undefined;
822+let remoteMetadata: SlackDesktopRemoteMetadata | undefined;
779823780824try {
781825const preparedCredentialEnv = await prepareGatewayCredentialEnv({
@@ -855,13 +899,22 @@ export async function runMantisSlackDesktopSmoke(
855899if (!(await pathExists(videoPath))) {
856900videoPath = undefined;
857901}
902+remoteMetadata = await readRemoteMetadata(outputDir);
858903slackQaDir = path.join(outputDir, "slack-qa");
859904if (!(await pathExists(screenshotPath))) {
860905throw new Error("Slack desktop screenshot was not copied back from Crabbox.");
861906}
862-if (remoteRunError) {
907+const gatewaySetupCompleted =
908+gatewaySetup && remoteMetadata?.qaExitCode === 0 && remoteMetadata.gatewayAlive === true;
909+if (remoteRunError && !gatewaySetupCompleted) {
863910throw remoteRunError;
864911}
912+if (gatewaySetup && !gatewaySetupCompleted) {
913+throw new Error("Slack desktop gateway setup did not report a live OpenClaw gateway.");
914+}
915+const ignoredRemoteRunError = remoteRunError
916+ ? `Crabbox returned a non-zero command status after the gateway setup completed: ${formatErrorMessage(remoteRunError)}`
917+ : undefined;
865918summary = {
866919artifacts: {
867920 reportPath,
@@ -882,9 +935,10 @@ export async function runMantisSlackDesktopSmoke(
882935finishedAt: new Date().toISOString(),
883936 outputDir,
884937 remoteOutputDir,
885- slackUrl,
938+slackUrl: trimToValue(remoteMetadata?.openedUrl) ?? slackUrl,
886939startedAt: startedAt.toISOString(),
887940status: "pass",
941+warning: ignoredRemoteRunError,
888942};
889943return {
890944 outputDir,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。