mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
fix: fix kitty proto on old terminals
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Avoid leaving advanced keyboard modes enabled after exiting the TUI in mintty and MINGW terminals.
|
||||
@@ -67,20 +67,21 @@ import { createTuiApi } from "@/cli/cmd/tui/plugin/api"
|
||||
import { TuiPluginRuntime } from "@/cli/cmd/tui/plugin/runtime"
|
||||
import type { RouteMap } from "@/cli/cmd/tui/plugin/api"
|
||||
import { FormatError, FormatUnknownError } from "@/cli/error"
|
||||
import { resetTerminalState } from "@/kilocode/cli/cmd/tui/util/terminal" // kilocode_change
|
||||
import { kitty, resetTerminalState } from "@/kilocode/cli/cmd/tui/util/terminal" // kilocode_change
|
||||
|
||||
import type { EventSource } from "./context/sdk"
|
||||
import { DialogVariant } from "./component/dialog-variant"
|
||||
|
||||
function rendererConfig(_config: TuiConfig.Info): CliRendererConfig {
|
||||
const mouseEnabled = !Flag.KILO_DISABLE_MOUSE && (_config.mouse ?? true)
|
||||
const keyboard = kitty() // kilocode_change
|
||||
|
||||
return {
|
||||
externalOutputMode: "passthrough",
|
||||
targetFps: 60,
|
||||
gatherStats: false,
|
||||
exitOnCtrlC: false,
|
||||
useKittyKeyboard: {},
|
||||
...(keyboard ? { useKittyKeyboard: {} } : {}), // kilocode_change
|
||||
autoFocus: false,
|
||||
openConsoleOnError: false,
|
||||
useMouse: mouseEnabled,
|
||||
|
||||
@@ -1,21 +1,48 @@
|
||||
// kilocode_change - new file
|
||||
/**
|
||||
* Write escape sequences to disable all mouse tracking modes and reset terminal state.
|
||||
* Write escape sequences to disable terminal input modes and reset terminal state.
|
||||
* This is a safety net to ensure the terminal is clean after exit, even if the renderer's
|
||||
* cleanup didn't flush properly (e.g. on Windows).
|
||||
*/
|
||||
export function resetTerminalState() {
|
||||
const sequences = [
|
||||
function truthy(key: string) {
|
||||
const value = process.env[key]?.toLowerCase()
|
||||
return value === "true" || value === "1"
|
||||
}
|
||||
|
||||
export function kitty() {
|
||||
if (truthy("KILO_DISABLE_KITTY_KEYBOARD")) return false
|
||||
if (truthy("KILO_ENABLE_KITTY_KEYBOARD")) return true
|
||||
|
||||
const term = process.env.TERM_PROGRAM?.toLowerCase()
|
||||
const system = process.env.MSYSTEM?.toLowerCase()
|
||||
|
||||
if (term === "mintty") return false
|
||||
if (system) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export function sequences() {
|
||||
return [
|
||||
"\x1b[?1000l", // disable normal mouse tracking
|
||||
"\x1b[?1002l", // disable button-event mouse tracking
|
||||
"\x1b[?1003l", // disable any-event mouse tracking (all movement)
|
||||
"\x1b[?1006l", // disable SGR extended mouse mode
|
||||
"\x1b[?1015l", // disable RXVT mouse mode
|
||||
"\x1b[<u", // pop/disable Kitty keyboard protocol
|
||||
"\x1b[?2004l", // disable bracketed paste
|
||||
"\x1b[?1004l", // disable focus tracking
|
||||
"\x1b[?1l", // disable application cursor keys
|
||||
"\x1b>", // disable application keypad mode
|
||||
"\x1b[?66l", // disable numeric keypad application mode
|
||||
"\x1b[>4;0m", // reset xterm modifyOtherKeys
|
||||
...(kitty() ? ["\x1b[<u"] : []), // pop/disable Kitty keyboard protocol
|
||||
"\x1b[?25h", // show cursor
|
||||
"\x1b[0m", // reset text attributes
|
||||
]
|
||||
}
|
||||
|
||||
export function resetTerminalState() {
|
||||
try {
|
||||
process.stdout.write(sequences.join(""))
|
||||
process.stdout.write(sequences().join(""))
|
||||
} catch (err) {
|
||||
console.error("resetTerminalState failed", err)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import { afterEach, expect, test } from "bun:test"
|
||||
import { kitty, sequences } from "../../src/kilocode/cli/cmd/tui/util/terminal"
|
||||
|
||||
const keys = ["TERM_PROGRAM", "MSYSTEM", "KILO_DISABLE_KITTY_KEYBOARD", "KILO_ENABLE_KITTY_KEYBOARD"] as const
|
||||
type Key = (typeof keys)[number]
|
||||
const saved = Object.fromEntries(keys.map((key) => [key, process.env[key]])) as Record<Key, string | undefined>
|
||||
|
||||
function env(input: Partial<Record<Key, string | undefined>>) {
|
||||
for (const key of keys) {
|
||||
const value = input[key]
|
||||
if (value === undefined) {
|
||||
delete process.env[key]
|
||||
continue
|
||||
}
|
||||
process.env[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
function restore() {
|
||||
for (const key of keys) {
|
||||
const value = saved[key]
|
||||
if (value === undefined) {
|
||||
delete process.env[key]
|
||||
continue
|
||||
}
|
||||
process.env[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
restore()
|
||||
})
|
||||
|
||||
test("enables Kitty keyboard reset by default", () => {
|
||||
env({})
|
||||
|
||||
expect(kitty()).toBe(true)
|
||||
expect(sequences()).toContain("\x1b[<u")
|
||||
})
|
||||
|
||||
test("disables Kitty keyboard in mintty", () => {
|
||||
env({ TERM_PROGRAM: "mintty" })
|
||||
|
||||
expect(kitty()).toBe(false)
|
||||
expect(sequences()).not.toContain("\x1b[<u")
|
||||
})
|
||||
|
||||
test("disables Kitty keyboard in MSYS shells", () => {
|
||||
env({ MSYSTEM: "MINGW64" })
|
||||
|
||||
expect(kitty()).toBe(false)
|
||||
expect(sequences()).not.toContain("\x1b[<u")
|
||||
})
|
||||
|
||||
test("allows explicitly enabling Kitty keyboard", () => {
|
||||
env({ KILO_ENABLE_KITTY_KEYBOARD: "1", MSYSTEM: "MINGW64" })
|
||||
|
||||
expect(kitty()).toBe(true)
|
||||
expect(sequences()).toContain("\x1b[<u")
|
||||
})
|
||||
|
||||
test("allows explicitly disabling Kitty keyboard", () => {
|
||||
env({ KILO_DISABLE_KITTY_KEYBOARD: "1", KILO_ENABLE_KITTY_KEYBOARD: "1" })
|
||||
|
||||
expect(kitty()).toBe(false)
|
||||
expect(sequences()).not.toContain("\x1b[<u")
|
||||
})
|
||||
|
||||
test("resets common terminal input modes", () => {
|
||||
env({ KILO_DISABLE_KITTY_KEYBOARD: "1" })
|
||||
|
||||
expect(sequences()).toEqual(
|
||||
expect.arrayContaining([
|
||||
"\x1b[?1000l",
|
||||
"\x1b[?1002l",
|
||||
"\x1b[?1003l",
|
||||
"\x1b[?1006l",
|
||||
"\x1b[?1015l",
|
||||
"\x1b[?2004l",
|
||||
"\x1b[?1004l",
|
||||
"\x1b[?1l",
|
||||
"\x1b>",
|
||||
"\x1b[?66l",
|
||||
"\x1b[>4;0m",
|
||||
"\x1b[?25h",
|
||||
"\x1b[0m",
|
||||
]),
|
||||
)
|
||||
})
|
||||
@@ -7,12 +7,12 @@ export const iconNames = [
|
||||
"zai",
|
||||
"zai-coding-plan",
|
||||
"xiaomi",
|
||||
"xiaomi-token-plan-sgp", // kilocode_change
|
||||
"xiaomi-token-plan-cn", // kilocode_change
|
||||
"xiaomi-token-plan-ams", // kilocode_change
|
||||
"xiaomi-token-plan-sgp",
|
||||
"xiaomi-token-plan-cn",
|
||||
"xiaomi-token-plan-ams",
|
||||
"xai",
|
||||
"wandb",
|
||||
"wafer.ai", // kilocode_change
|
||||
"wafer.ai",
|
||||
"vultr",
|
||||
"vivgrid",
|
||||
"vercel",
|
||||
@@ -20,8 +20,8 @@ export const iconNames = [
|
||||
"v0",
|
||||
"upstage",
|
||||
"togetherai",
|
||||
"the-grid-ai", // kilocode_change
|
||||
"tencent-tokenhub", // kilocode_change
|
||||
"the-grid-ai",
|
||||
"tencent-tokenhub",
|
||||
"tencent-coding-plan",
|
||||
"synthetic",
|
||||
"submodel",
|
||||
@@ -32,7 +32,7 @@ export const iconNames = [
|
||||
"scaleway",
|
||||
"sap-ai-core",
|
||||
"requesty",
|
||||
"regolo-ai", // kilocode_change
|
||||
"regolo-ai",
|
||||
"qiniu-ai",
|
||||
"qihang-ai",
|
||||
"privatemode-ai",
|
||||
@@ -48,7 +48,7 @@ export const iconNames = [
|
||||
"nvidia",
|
||||
"novita-ai",
|
||||
"nova",
|
||||
"neuralwatt", // kilocode_change
|
||||
"neuralwatt",
|
||||
"nebius",
|
||||
"nano-gpt",
|
||||
"morph",
|
||||
@@ -56,7 +56,7 @@ export const iconNames = [
|
||||
"moonshotai-cn",
|
||||
"modelscope",
|
||||
"moark",
|
||||
"mixlayer", // kilocode_change
|
||||
"mixlayer",
|
||||
"mistral",
|
||||
"minimax",
|
||||
"minimax-coding-plan",
|
||||
@@ -65,10 +65,10 @@ export const iconNames = [
|
||||
"meganova",
|
||||
"lucidquery",
|
||||
"lmstudio",
|
||||
"llmgateway", // kilocode_change
|
||||
"llmgateway",
|
||||
"llama",
|
||||
"kuae-cloud-coding-plan",
|
||||
"kiro", // kilocode_change
|
||||
"kiro",
|
||||
"kimi-for-coding",
|
||||
"kilo",
|
||||
"jiekou",
|
||||
@@ -77,7 +77,7 @@ export const iconNames = [
|
||||
"inception",
|
||||
"iflowcn",
|
||||
"huggingface",
|
||||
"hpc-ai", // kilocode_change
|
||||
"hpc-ai",
|
||||
"helicone",
|
||||
"groq",
|
||||
"google",
|
||||
@@ -86,7 +86,7 @@ export const iconNames = [
|
||||
"gitlab",
|
||||
"github-models",
|
||||
"github-copilot",
|
||||
"frogbot", // kilocode_change
|
||||
"frogbot",
|
||||
"friendli",
|
||||
"firmware",
|
||||
"fireworks-ai",
|
||||
@@ -94,7 +94,7 @@ export const iconNames = [
|
||||
"evroc",
|
||||
"drun",
|
||||
"dinference",
|
||||
"digitalocean", // kilocode_change
|
||||
"digitalocean",
|
||||
"deepseek",
|
||||
"deepinfra",
|
||||
"cortecs",
|
||||
@@ -117,7 +117,7 @@ export const iconNames = [
|
||||
"alibaba-coding-plan-cn",
|
||||
"alibaba-cn",
|
||||
"aihubmix",
|
||||
"abliteration-ai", // kilocode_change
|
||||
"abliteration-ai",
|
||||
"abacus",
|
||||
"302ai",
|
||||
] as const
|
||||
|
||||
Reference in New Issue
Block a user