diff --git a/scripts/lib/docker-e2e-logs.sh b/scripts/lib/docker-e2e-logs.sh index b6e83f0434be..3fd32148e89c 100644 --- a/scripts/lib/docker-e2e-logs.sh +++ b/scripts/lib/docker-e2e-logs.sh @@ -153,7 +153,7 @@ run_logged_print_heartbeat() { trap 'cleanup_heartbeat_command 130' INT trap 'cleanup_heartbeat_command 143' TERM trap 'cleanup_heartbeat_command 129' HUP - "$@" >"$log_file" 2>&1 & + "$@" <&0 >"$log_file" 2>&1 & command_pid=$! local started_at="$SECONDS" local next_heartbeat=$interval_seconds diff --git a/test/scripts/docker-build-helper.test.ts b/test/scripts/docker-build-helper.test.ts index c627cc900526..75e03fc08d68 100644 --- a/test/scripts/docker-build-helper.test.ts +++ b/test/scripts/docker-build-helper.test.ts @@ -2932,6 +2932,41 @@ output="$(docker_e2e_maybe_print_log_heartbeat plugins-run 1 1 "$TMPDIR/run.log" execFileSync("bash", ["-lc", script], { encoding: "utf8" }); }); + it("preserves heredoc stdin through Docker E2E heartbeat logging", () => { + const workDir = tempDirs.make("openclaw-docker-e2e-log-stdin-"); + const script = repoShell(workDir)` + +source "$ROOT_DIR/scripts/lib/docker-e2e-logs.sh" + +run_logged_print_heartbeat plugins-run 30 bash -s <<'SH' +printf "first payload line\\nsecond payload line\\n" +SH +`; + + expect(execFileSync("bash", ["-lc", script], { encoding: "utf8" })).toBe( + "first payload line\nsecond payload line\n", + ); + }); + + it("preserves failing heredoc output and status through Docker E2E heartbeat logging", () => { + const workDir = tempDirs.make("openclaw-docker-e2e-log-failing-stdin-"); + const script = repoShell(workDir)` + +source "$ROOT_DIR/scripts/lib/docker-e2e-logs.sh" + +run_logged_print_heartbeat plugins-run 30 bash -s <<'SH' +printf "captured failure output\\n" +exit 37 +SH +`; + + const result = spawnSync("bash", ["-lc", script], { encoding: "utf8" }); + + expect(result.status).toBe(37); + expect(result.stdout).toBe("captured failure output\n"); + expect(result.stderr).toBe(""); + }); + it("cleans the heartbeat command when the wrapper is terminated", () => { const workDir = tempDirs.make("openclaw-docker-e2e-log-term-cleanup-"); const script = repoShell(workDir)`