SPB Git

spb/khaelor Public

KHAELOR — a terminal-native autonomous engineering agent powered by Anthropic.

TypeScript 82.9% HTML 14.9% CSS 1.1% JavaScript 0.7%
3.0 KB · 87 lines typescript
Raw Blame History
1/**2 * KHAELOR3 * File: tests/tui/input.test.ts4 * Description: Key decoder tests — control keys, escape sequences, bracketed paste across chunks, reply filtering.5 *6 * Author: Simon-Pierre Boucher7 * Contact: contact@spboucher.ai8 */910import { describe, expect, it } from "vitest";11import { KeyDecoder } from "../../src/tui/renderer/input.js";1213function decode(...chunks: string[]) {14  const d = new KeyDecoder();15  return chunks.flatMap((c) => d.push(c));16}1718describe("KeyDecoder", () => {19  it("decodes printable characters including unicode", () => {20    expect(decode("aé🎉")).toEqual([21      { type: "char", ch: "a" },22      { type: "char", ch: "é" },23      { type: "char", ch: "🎉" },24    ]);25  });2627  it("decodes enter, tab, backspace, ctrl keys", () => {28    expect(decode("\r")).toEqual([{ type: "enter" }]);29    expect(decode("\t")).toEqual([{ type: "tab" }]);30    expect(decode("\x7f")).toEqual([{ type: "backspace" }]);31    expect(decode("\x01")).toEqual([{ type: "ctrl", ch: "a" }]);32    expect(decode("\x0b")).toEqual([{ type: "ctrl", ch: "k" }]);33    expect(decode("\x1f")).toEqual([{ type: "ctrl", ch: "_" }]);34    expect(decode("\n")).toEqual([{ type: "ctrl", ch: "j" }]);35  });3637  it("decodes arrows with alt/ctrl modifiers", () => {38    expect(decode("\x1b[A")).toEqual([{ type: "arrow", key: "up", alt: false, ctrl: false }]);39    expect(decode("\x1b[1;5C")).toEqual([{ type: "arrow", key: "right", alt: false, ctrl: true }]);40    expect(decode("\x1b[1;3D")).toEqual([{ type: "arrow", key: "left", alt: true, ctrl: false }]);41  });4243  it("decodes home/end/delete variants", () => {44    expect(decode("\x1b[H")).toEqual([{ type: "home" }]);45    expect(decode("\x1b[4~")).toEqual([{ type: "end" }]);46    expect(decode("\x1b[3~")).toEqual([{ type: "delete" }]);47    expect(decode("\x1bOF")).toEqual([{ type: "end" }]);48  });4950  it("decodes alt-letter and alt-backspace", () => {51    expect(decode("\x1bb")).toEqual([{ type: "alt", ch: "b" }]);52    expect(decode("\x1b\x7f")).toEqual([{ type: "alt-backspace" }]);53  });5455  it("decodes kitty shift+enter", () => {56    expect(decode("\x1b[13;2u")).toEqual([{ type: "shift-enter" }]);57  });5859  it("treats a chunk ending on lone ESC as the Esc key", () => {60    expect(decode("\x1b")).toEqual([{ type: "esc" }]);61  });6263  it("reassembles a bracketed paste split across chunks", () => {64    expect(decode("\x1b[200~hello\nwor", "ld\x1b[201~")).toEqual([65      { type: "paste", text: "hello\nworld" },66    ]);67  });6869  it("handles a paste-end marker torn mid-sequence", () => {70    expect(decode("\x1b[200~abc\x1b[20", "1~x")).toEqual([71      { type: "paste", text: "abc" },72      { type: "char", ch: "x" },73    ]);74  });7576  it("silently drops terminal query replies (DECRQM, OSC 11)", () => {77    expect(decode("\x1b[?2026;1$y")).toEqual([]);78    expect(decode("\x1b]11;rgb:1c1c/1c1c/1c1c\x07")).toEqual([]);79  });8081  it("keeps a torn CSI across chunks and completes it", () => {82    expect(decode("\x1b[1;", "5C")).toEqual([83      { type: "arrow", key: "right", alt: false, ctrl: true },84    ]);85  });86});87