mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-29 18:12:52 +00:00
fix: fail loud when PTY cursor mode is unknown (#51490) (thanks @liuy)
* fix(process): auto-detect PTY cursor key mode for send-keys When a PTY session sends smkx (\x1b[?1h) or rmkx (\x1b[?1l) to switch cursor key mode, send-keys now detects this and encodes cursor keys accordingly. - smkx/rmkx detection in handleStdout before sanitizeBinaryOutput - cursorKeyMode stored in ProcessSession - encodeKeySequence accepts cursorKeyMode parameter - DECCKM_SS3_KEYS for application mode (arrows + home/end) - CSI sequences for normal mode - Modified keys (including alt) always use xterm modifier scheme - Extract detectCursorKeyMode for unit testing - Use lastIndexOf to find last toggle in chunk (later one wins) Fixes #51488 * fix: fail loud when PTY cursor mode is unknown (#51490) (thanks @liuy) * style: format process send-keys guard (#51490) (thanks @liuy) --------- Co-authored-by: Ayaan Zaidi <hi@obviy.us>
This commit is contained in:
@@ -4,9 +4,42 @@ const requestHeartbeatNowMock = vi.hoisted(() => vi.fn());
|
||||
const enqueueSystemEventMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
let buildExecExitOutcome: typeof import("./bash-tools.exec-runtime.js").buildExecExitOutcome;
|
||||
let detectCursorKeyMode: typeof import("./bash-tools.exec-runtime.js").detectCursorKeyMode;
|
||||
let emitExecSystemEvent: typeof import("./bash-tools.exec-runtime.js").emitExecSystemEvent;
|
||||
let formatExecFailureReason: typeof import("./bash-tools.exec-runtime.js").formatExecFailureReason;
|
||||
|
||||
describe("detectCursorKeyMode", () => {
|
||||
beforeEach(async () => {
|
||||
({ detectCursorKeyMode } = await import("./bash-tools.exec-runtime.js"));
|
||||
});
|
||||
|
||||
it("returns null when no toggle found", () => {
|
||||
expect(detectCursorKeyMode("hello world")).toBe(null);
|
||||
expect(detectCursorKeyMode("")).toBe(null);
|
||||
});
|
||||
|
||||
it("detects smkx (application mode)", () => {
|
||||
expect(detectCursorKeyMode("\x1b[?1h")).toBe("application");
|
||||
expect(detectCursorKeyMode("\x1b[?1h\x1b=")).toBe("application");
|
||||
expect(detectCursorKeyMode("before \x1b[?1h after")).toBe("application");
|
||||
});
|
||||
|
||||
it("detects rmkx (normal mode)", () => {
|
||||
expect(detectCursorKeyMode("\x1b[?1l")).toBe("normal");
|
||||
expect(detectCursorKeyMode("\x1b[?1l\x1b>")).toBe("normal");
|
||||
expect(detectCursorKeyMode("before \x1b[?1l after")).toBe("normal");
|
||||
});
|
||||
|
||||
it("last toggle wins when both present", () => {
|
||||
// smkx first, then rmkx - should be normal
|
||||
expect(detectCursorKeyMode("\x1b[?1h\x1b[?1l")).toBe("normal");
|
||||
// rmkx first, then smkx - should be application
|
||||
expect(detectCursorKeyMode("\x1b[?1l\x1b[?1h")).toBe("application");
|
||||
// Multiple toggles - last one wins
|
||||
expect(detectCursorKeyMode("\x1b[?1h\x1b[?1l\x1b[?1h")).toBe("application");
|
||||
});
|
||||
});
|
||||
|
||||
describe("emitExecSystemEvent", () => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
|
||||
Reference in New Issue
Block a user