mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 21:07:01 -06:00
fix(tui): report one terminal outcome for local shell failures (#118452)
Co-authored-by: Peter Steinberger <steipete@macos.shared>
This commit is contained in:
committed by
GitHub
parent
763c97b2de
commit
c1cbcf047b
@@ -1,5 +1,7 @@
|
||||
// Verifies local shell process handling for TUI local mode.
|
||||
import { spawn } from "node:child_process";
|
||||
import { EventEmitter } from "node:events";
|
||||
import { join } from "node:path";
|
||||
import type { OverlayHandle } from "@earendil-works/pi-tui";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { createLocalShellRunner } from "./tui-local-shell.js";
|
||||
@@ -242,6 +244,28 @@ describe("createLocalShellRunner", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("finishes a failed child before reporting the next local command", async () => {
|
||||
const harness = createShellHarness({
|
||||
spawnCommand: spawn,
|
||||
getCwd: vi
|
||||
.fn(() => process.cwd())
|
||||
.mockReturnValueOnce(join(process.cwd(), ".missing-openclaw-local-shell-directory")),
|
||||
});
|
||||
|
||||
const failedRun = harness.runLocalShellLine("!echo first");
|
||||
harness.getLastSelector()?.onSelect?.({ value: "yes", label: "Yes" });
|
||||
await failedRun;
|
||||
await harness.runLocalShellLine("!echo second");
|
||||
|
||||
expect(harness.messages.filter((message) => message.startsWith("[local]"))).toEqual([
|
||||
"[local] $ echo first",
|
||||
expect.stringContaining("[local] error: "),
|
||||
"[local] $ echo second",
|
||||
"[local] second",
|
||||
"[local] exit 0",
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not crash when stdout or stderr emit an error event", async () => {
|
||||
const stdout = new EventEmitter();
|
||||
const stderr = new EventEmitter();
|
||||
|
||||
@@ -131,9 +131,10 @@ export function createLocalShellRunner(deps: LocalShellDeps) {
|
||||
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
let error: Error | undefined;
|
||||
const stdoutDecoder = new StringDecoder("utf8");
|
||||
const stderrDecoder = new StringDecoder("utf8");
|
||||
// Output pipes may fail independently; child close/error remains authoritative.
|
||||
// Pipe errors are incidental; close owns completion after any recorded spawn error.
|
||||
const ignoreOutputStreamError = () => {};
|
||||
child.stdout.on("error", ignoreOutputStreamError);
|
||||
child.stderr.on("error", ignoreOutputStreamError);
|
||||
@@ -160,15 +161,14 @@ export function createLocalShellRunner(deps: LocalShellDeps) {
|
||||
deps.chatLog.addSystem(`[local] ${lineLocal}`);
|
||||
}
|
||||
}
|
||||
deps.chatLog.addSystem(`[local] exit ${code ?? "?"}${signal ? ` (signal ${signal})` : ""}`);
|
||||
const status = error ? `error: ${formatTuiErrorMessage(error)}` : `exit ${code ?? "?"}`;
|
||||
deps.chatLog.addSystem(`[local] ${status}${signal ? ` (signal ${signal})` : ""}`);
|
||||
deps.tui.requestRender();
|
||||
resolve();
|
||||
});
|
||||
|
||||
child.on("error", (err) => {
|
||||
deps.chatLog.addSystem(`[local] error: ${formatTuiErrorMessage(err)}`);
|
||||
deps.tui.requestRender();
|
||||
resolve();
|
||||
error = err;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user