@greppleai/grip-tui 0.0.1 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"native-modifiers.d.ts","sourceRoot":"","sources":["../src/native-modifiers.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AA4CrE,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAQjE","sourcesContent":["import { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst cjsRequire = createRequire(import.meta.url);\n\nexport type ModifierKey = \"shift\" | \"command\" | \"control\" | \"option\";\n\ntype NativeModifiersHelper = {\n\tisModifierPressed: (name: ModifierKey) => boolean;\n};\n\nlet nativeModifiersHelper: NativeModifiersHelper | null | undefined;\n\nfunction isNativeModifiersHelper(value: unknown): value is NativeModifiersHelper {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst candidate = (value as { isModifierPressed?: unknown }).isModifierPressed;\n\treturn typeof candidate === \"function\";\n}\n\nfunction loadNativeModifiersHelper(): NativeModifiersHelper | undefined {\n\tif (nativeModifiersHelper !== undefined) return nativeModifiersHelper ?? undefined;\n\tnativeModifiersHelper = null;\n\tif (process.platform !== \"darwin\") return undefined;\n\tconst arch = process.arch;\n\tif (arch !== \"x64\" && arch !== \"arm64\") return undefined;\n\n\tconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\tconst nativePath = path.join(\"native\", \"darwin\", \"prebuilds\", `darwin-${arch}`, \"darwin-modifiers.node\");\n\tconst candidates = [\n\t\tpath.join(moduleDir, \"..\", nativePath),\n\t\tpath.join(moduleDir, nativePath),\n\t\tpath.join(path.dirname(process.execPath), nativePath),\n\t];\n\n\tfor (const modulePath of candidates) {\n\t\ttry {\n\t\t\tconst helper = cjsRequire(modulePath) as unknown;\n\t\t\tif (isNativeModifiersHelper(helper)) {\n\t\t\t\tnativeModifiersHelper = helper;\n\t\t\t\treturn helper;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Try the next possible packaging location.\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nexport function isNativeModifierPressed(key: ModifierKey): boolean {\n\tconst helper = loadNativeModifiersHelper();\n\tif (!helper) return false;\n\ttry {\n\t\treturn helper.isModifierPressed(key) === true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n"]}
1
+ {"version":3,"file":"native-modifiers.d.ts","sourceRoot":"","sources":["../src/native-modifiers.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AA4CrE,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAQjE","sourcesContent":["import { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst cjsRequire = createRequire(import.meta.url);\n\nexport type ModifierKey = \"shift\" | \"command\" | \"control\" | \"option\";\n\ntype NativeModifiersHelper = {\n\tisModifierPressed: (name: ModifierKey) => boolean;\n};\n\nlet nativeModifiersHelper: NativeModifiersHelper | null | undefined;\n\nfunction isNativeModifiersHelper(value: unknown): value is NativeModifiersHelper {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst candidate = (value as { isModifierPressed?: unknown }).isModifierPressed;\n\treturn typeof candidate === \"function\";\n}\n\nfunction loadNativeModifiersHelper(): NativeModifiersHelper | undefined {\n\tif (nativeModifiersHelper !== undefined) return nativeModifiersHelper ?? undefined;\n\tnativeModifiersHelper = null;\n\tif (process.platform !== \"darwin\") return undefined;\n\tconst arch = process.arch;\n\tif (arch !== \"x64\" && arch !== \"arm64\") return undefined;\n\n\tconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\tconst nativePath = path.join(\"native\", \"darwin\", \"prebuilds\", `darwin-${arch}`, \"darwin-modifiers.node\");\n\tconst candidates = [\n\t\tpath.join(moduleDir, \"..\", nativePath),\n\t\tpath.join(moduleDir, nativePath),\n\t\tpath.join(process.env.GRIP_EMBEDDED_ASSET_DIR || path.dirname(process.execPath), nativePath),\n\t];\n\n\tfor (const modulePath of candidates) {\n\t\ttry {\n\t\t\tconst helper = cjsRequire(modulePath) as unknown;\n\t\t\tif (isNativeModifiersHelper(helper)) {\n\t\t\t\tnativeModifiersHelper = helper;\n\t\t\t\treturn helper;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Try the next possible packaging location.\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nexport function isNativeModifierPressed(key: ModifierKey): boolean {\n\tconst helper = loadNativeModifiersHelper();\n\tif (!helper) return false;\n\ttry {\n\t\treturn helper.isModifierPressed(key) === true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n"]}
@@ -23,7 +23,7 @@ function loadNativeModifiersHelper() {
23
23
  const candidates = [
24
24
  path.join(moduleDir, "..", nativePath),
25
25
  path.join(moduleDir, nativePath),
26
- path.join(path.dirname(process.execPath), nativePath),
26
+ path.join(process.env.GRIP_EMBEDDED_ASSET_DIR || path.dirname(process.execPath), nativePath),
27
27
  ];
28
28
  for (const modulePath of candidates) {
29
29
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"native-modifiers.js","sourceRoot":"","sources":["../src/native-modifiers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AAQlD,IAAI,qBAA+D,CAAC;AAEpE,SAAS,uBAAuB,CAAC,KAAc,EAAkC;IAChF,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,SAAS,GAAI,KAAyC,CAAC,iBAAiB,CAAC;IAC/E,OAAO,OAAO,SAAS,KAAK,UAAU,CAAC;AAAA,CACvC;AAED,SAAS,yBAAyB,GAAsC;IACvE,IAAI,qBAAqB,KAAK,SAAS;QAAE,OAAO,qBAAqB,IAAI,SAAS,CAAC;IACnF,qBAAqB,GAAG,IAAI,CAAC;IAC7B,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACpD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAC1B,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,SAAS,CAAC;IAEzD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,IAAI,EAAE,EAAE,uBAAuB,CAAC,CAAC;IACzG,MAAM,UAAU,GAAG;QAClB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC;KACrD,CAAC;IAEF,KAAK,MAAM,UAAU,IAAI,UAAU,EAAE,CAAC;QACrC,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAY,CAAC;YACjD,IAAI,uBAAuB,CAAC,MAAM,CAAC,EAAE,CAAC;gBACrC,qBAAqB,GAAG,MAAM,CAAC;gBAC/B,OAAO,MAAM,CAAC;YACf,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,4CAA4C;QAC7C,CAAC;IACF,CAAC;IAED,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,MAAM,UAAU,uBAAuB,CAAC,GAAgB,EAAW;IAClE,MAAM,MAAM,GAAG,yBAAyB,EAAE,CAAC;IAC3C,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,IAAI,CAAC;QACJ,OAAO,MAAM,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;AAAA,CACD","sourcesContent":["import { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst cjsRequire = createRequire(import.meta.url);\n\nexport type ModifierKey = \"shift\" | \"command\" | \"control\" | \"option\";\n\ntype NativeModifiersHelper = {\n\tisModifierPressed: (name: ModifierKey) => boolean;\n};\n\nlet nativeModifiersHelper: NativeModifiersHelper | null | undefined;\n\nfunction isNativeModifiersHelper(value: unknown): value is NativeModifiersHelper {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst candidate = (value as { isModifierPressed?: unknown }).isModifierPressed;\n\treturn typeof candidate === \"function\";\n}\n\nfunction loadNativeModifiersHelper(): NativeModifiersHelper | undefined {\n\tif (nativeModifiersHelper !== undefined) return nativeModifiersHelper ?? undefined;\n\tnativeModifiersHelper = null;\n\tif (process.platform !== \"darwin\") return undefined;\n\tconst arch = process.arch;\n\tif (arch !== \"x64\" && arch !== \"arm64\") return undefined;\n\n\tconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\tconst nativePath = path.join(\"native\", \"darwin\", \"prebuilds\", `darwin-${arch}`, \"darwin-modifiers.node\");\n\tconst candidates = [\n\t\tpath.join(moduleDir, \"..\", nativePath),\n\t\tpath.join(moduleDir, nativePath),\n\t\tpath.join(path.dirname(process.execPath), nativePath),\n\t];\n\n\tfor (const modulePath of candidates) {\n\t\ttry {\n\t\t\tconst helper = cjsRequire(modulePath) as unknown;\n\t\t\tif (isNativeModifiersHelper(helper)) {\n\t\t\t\tnativeModifiersHelper = helper;\n\t\t\t\treturn helper;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Try the next possible packaging location.\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nexport function isNativeModifierPressed(key: ModifierKey): boolean {\n\tconst helper = loadNativeModifiersHelper();\n\tif (!helper) return false;\n\ttry {\n\t\treturn helper.isModifierPressed(key) === true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n"]}
1
+ {"version":3,"file":"native-modifiers.js","sourceRoot":"","sources":["../src/native-modifiers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AAQlD,IAAI,qBAA+D,CAAC;AAEpE,SAAS,uBAAuB,CAAC,KAAc,EAAkC;IAChF,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,SAAS,GAAI,KAAyC,CAAC,iBAAiB,CAAC;IAC/E,OAAO,OAAO,SAAS,KAAK,UAAU,CAAC;AAAA,CACvC;AAED,SAAS,yBAAyB,GAAsC;IACvE,IAAI,qBAAqB,KAAK,SAAS;QAAE,OAAO,qBAAqB,IAAI,SAAS,CAAC;IACnF,qBAAqB,GAAG,IAAI,CAAC;IAC7B,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACpD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAC1B,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,SAAS,CAAC;IAEzD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,IAAI,EAAE,EAAE,uBAAuB,CAAC,CAAC;IACzG,MAAM,UAAU,GAAG;QAClB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC;KAC5F,CAAC;IAEF,KAAK,MAAM,UAAU,IAAI,UAAU,EAAE,CAAC;QACrC,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAY,CAAC;YACjD,IAAI,uBAAuB,CAAC,MAAM,CAAC,EAAE,CAAC;gBACrC,qBAAqB,GAAG,MAAM,CAAC;gBAC/B,OAAO,MAAM,CAAC;YACf,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,4CAA4C;QAC7C,CAAC;IACF,CAAC;IAED,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,MAAM,UAAU,uBAAuB,CAAC,GAAgB,EAAW;IAClE,MAAM,MAAM,GAAG,yBAAyB,EAAE,CAAC;IAC3C,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,IAAI,CAAC;QACJ,OAAO,MAAM,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;AAAA,CACD","sourcesContent":["import { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst cjsRequire = createRequire(import.meta.url);\n\nexport type ModifierKey = \"shift\" | \"command\" | \"control\" | \"option\";\n\ntype NativeModifiersHelper = {\n\tisModifierPressed: (name: ModifierKey) => boolean;\n};\n\nlet nativeModifiersHelper: NativeModifiersHelper | null | undefined;\n\nfunction isNativeModifiersHelper(value: unknown): value is NativeModifiersHelper {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst candidate = (value as { isModifierPressed?: unknown }).isModifierPressed;\n\treturn typeof candidate === \"function\";\n}\n\nfunction loadNativeModifiersHelper(): NativeModifiersHelper | undefined {\n\tif (nativeModifiersHelper !== undefined) return nativeModifiersHelper ?? undefined;\n\tnativeModifiersHelper = null;\n\tif (process.platform !== \"darwin\") return undefined;\n\tconst arch = process.arch;\n\tif (arch !== \"x64\" && arch !== \"arm64\") return undefined;\n\n\tconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\tconst nativePath = path.join(\"native\", \"darwin\", \"prebuilds\", `darwin-${arch}`, \"darwin-modifiers.node\");\n\tconst candidates = [\n\t\tpath.join(moduleDir, \"..\", nativePath),\n\t\tpath.join(moduleDir, nativePath),\n\t\tpath.join(process.env.GRIP_EMBEDDED_ASSET_DIR || path.dirname(process.execPath), nativePath),\n\t];\n\n\tfor (const modulePath of candidates) {\n\t\ttry {\n\t\t\tconst helper = cjsRequire(modulePath) as unknown;\n\t\t\tif (isNativeModifiersHelper(helper)) {\n\t\t\t\tnativeModifiersHelper = helper;\n\t\t\t\treturn helper;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Try the next possible packaging location.\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nexport function isNativeModifierPressed(key: ModifierKey): boolean {\n\tconst helper = loadNativeModifiersHelper();\n\tif (!helper) return false;\n\ttry {\n\t\treturn helper.isModifierPressed(key) === true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../src/terminal.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { setKittyProtocolActive } from \"./keys.ts\";\nimport { isNativeModifierPressed } from \"./native-modifiers.ts\";\nimport { StdinBuffer } from \"./stdin-buffer.ts\";\nimport { sanitizeTerminalControlPayload } from \"./terminal-control.ts\";\n\nconst cjsRequire = createRequire(import.meta.url);\n\nconst TERMINAL_PROGRESS_KEEPALIVE_MS = 1000;\nconst TERMINAL_PROGRESS_ACTIVE_SEQUENCE = \"\\x1b]9;4;3\\x07\";\nconst TERMINAL_PROGRESS_CLEAR_SEQUENCE = \"\\x1b]9;4;0\\x07\";\nconst APPLE_TERMINAL_SHIFT_ENTER_SEQUENCE = \"\\x1b[13;2u\";\nconst DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS = 7;\nconst KITTY_KEYBOARD_PROTOCOL_FALLBACK_TIMEOUT_MS = 150;\nconst KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS = 150;\nconst KITTY_KEYBOARD_PROTOCOL_QUERY = `\\x1b[>${DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS}u\\x1b[?u\\x1b[c`;\n\nexport type KeyboardProtocolNegotiationSequence =\n\t| { type: \"kitty-flags\"; flags: number }\n\t| { type: \"device-attributes\" };\n\nexport function parseKeyboardProtocolNegotiationSequence(\n\tsequence: string,\n): KeyboardProtocolNegotiationSequence | undefined {\n\tconst kittyFlags = sequence.match(/^\\x1b\\[\\?(\\d+)u$/);\n\tif (kittyFlags) {\n\t\treturn { type: \"kitty-flags\", flags: Number.parseInt(kittyFlags[1]!, 10) };\n\t}\n\tif (/^\\x1b\\[\\?[\\d;]*c$/.test(sequence)) {\n\t\treturn { type: \"device-attributes\" };\n\t}\n\treturn undefined;\n}\n\nfunction isKeyboardProtocolNegotiationSequencePrefix(sequence: string, allowBareEscapePrefix: boolean): boolean {\n\treturn (allowBareEscapePrefix && sequence === \"\\x1b\") || sequence === \"\\x1b[\" || /^\\x1b\\[\\?[\\d;]*$/.test(sequence);\n}\n\nexport function isAppleTerminalSession(): boolean {\n\treturn process.platform === \"darwin\" && process.env.TERM_PROGRAM === \"Apple_Terminal\";\n}\n\nexport function normalizeAppleTerminalInput(data: string, isAppleTerminal: boolean, isShiftPressed: boolean): string {\n\tif (isAppleTerminal && data === \"\\r\" && isShiftPressed) return APPLE_TERMINAL_SHIFT_ENTER_SEQUENCE;\n\treturn data;\n}\n\n/**\n * Minimal terminal interface for TUI\n */\nexport interface Terminal {\n\t// Start the terminal with input and resize handlers\n\tstart(onInput: (data: string) => void, onResize: () => void): void;\n\n\t// Stop the terminal and restore state\n\tstop(): void;\n\n\t/**\n\t * Drain stdin before exiting to prevent Kitty key release events from\n\t * leaking to the parent shell over slow SSH connections.\n\t * @param maxMs - Maximum time to drain (default: 1000ms)\n\t * @param idleMs - Exit early if no input arrives within this time (default: 50ms)\n\t */\n\tdrainInput(maxMs?: number, idleMs?: number): Promise<void>;\n\n\t// Write output to terminal\n\twrite(data: string): void;\n\n\t// Get terminal dimensions\n\tget columns(): number;\n\tget rows(): number;\n\n\t// Whether Kitty keyboard protocol is active\n\tget kittyProtocolActive(): boolean;\n\n\t// Cursor positioning (relative to current position)\n\tmoveBy(lines: number): void; // Move cursor up (negative) or down (positive) by N lines\n\n\t// Cursor visibility\n\thideCursor(): void; // Hide the cursor\n\tshowCursor(): void; // Show the cursor\n\n\t// Clear operations\n\tclearLine(): void; // Clear current line\n\tclearFromCursor(): void; // Clear from cursor to end of screen\n\tclearScreen(): void; // Clear entire screen and move cursor to (0,0)\n\n\t// Title operations\n\tsetTitle(title: string): void; // Set terminal window title\n\n\t// Progress indicator (OSC 9;4)\n\tsetProgress(active: boolean): void;\n}\n\n/**\n * Real terminal using process.stdin/stdout\n */\nexport class ProcessTerminal implements Terminal {\n\tprivate wasRaw = false;\n\tprivate started = false;\n\tprivate inputHandler?: (data: string) => void;\n\tprivate resizeHandler?: () => void;\n\tprivate _kittyProtocolActive = false;\n\tprivate _modifyOtherKeysActive = false;\n\tprivate keyboardProtocolPushed = false;\n\tprivate keyboardProtocolNegotiationPending = false;\n\tprivate keyboardProtocolLateResponsePending = false;\n\tprivate keyboardProtocolNegotiationBuffer = \"\";\n\tprivate keyboardProtocolFallbackTimer?: ReturnType<typeof setTimeout>;\n\tprivate keyboardProtocolBufferFlushTimer?: ReturnType<typeof setTimeout>;\n\tprivate stdinBuffer?: StdinBuffer;\n\tprivate stdinDataHandler?: (data: string) => void;\n\tprivate progressInterval?: ReturnType<typeof setInterval>;\n\tprivate writeLogPath = (() => {\n\t\tconst env = process.env.GRIP_TUI_WRITE_LOG || \"\";\n\t\tif (!env) return \"\";\n\t\ttry {\n\t\t\tif (fs.statSync(env).isDirectory()) {\n\t\t\t\tconst now = new Date();\n\t\t\t\tconst ts = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, \"0\")}-${String(now.getDate()).padStart(2, \"0\")}_${String(now.getHours()).padStart(2, \"0\")}-${String(now.getMinutes()).padStart(2, \"0\")}-${String(now.getSeconds()).padStart(2, \"0\")}`;\n\t\t\t\treturn path.join(env, `tui-${ts}-${process.pid}.log`);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Not an existing directory - use as-is (file path)\n\t\t}\n\t\treturn env;\n\t})();\n\n\tget kittyProtocolActive(): boolean {\n\t\treturn this._kittyProtocolActive;\n\t}\n\n\tstart(onInput: (data: string) => void, onResize: () => void): void {\n\t\tif (this.started) {\n\t\t\tthis.inputHandler = onInput;\n\t\t\tif (this.resizeHandler !== onResize) {\n\t\t\t\tif (this.resizeHandler) process.stdout.removeListener(\"resize\", this.resizeHandler);\n\t\t\t\tthis.resizeHandler = onResize;\n\t\t\t\tprocess.stdout.on(\"resize\", onResize);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis.started = true;\n\t\tthis.inputHandler = onInput;\n\t\tthis.resizeHandler = onResize;\n\t\t// Save previous state and enable raw mode\n\t\tthis.wasRaw = process.stdin.isRaw || false;\n\t\tif (process.stdin.setRawMode) {\n\t\t\tprocess.stdin.setRawMode(true);\n\t\t}\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\t\tprocess.stdin.resume();\n\n\t\t// Enable bracketed paste mode - terminal will wrap pastes in \\x1b[200~ ... \\x1b[201~\n\t\tprocess.stdout.write(\"\\x1b[?2004h\");\n\n\t\t// Set up resize handler immediately\n\t\tprocess.stdout.on(\"resize\", this.resizeHandler);\n\n\t\t// Refresh terminal dimensions - they may be stale after suspend/resume\n\t\t// (SIGWINCH is lost while process is stopped). Unix only.\n\t\tif (process.platform !== \"win32\") {\n\t\t\tprocess.kill(process.pid, \"SIGWINCH\");\n\t\t}\n\n\t\t// On Windows, enable ENABLE_VIRTUAL_TERMINAL_INPUT so the console sends\n\t\t// VT escape sequences (e.g. \\x1b[Z for Shift+Tab) instead of raw console\n\t\t// events that lose modifier information. Must run AFTER setRawMode(true)\n\t\t// since that resets console mode flags.\n\t\tthis.enableWindowsVTInput();\n\n\t\t// Query and enable Kitty keyboard protocol\n\t\t// The query handler intercepts input temporarily, then installs the user's handler\n\t\t// See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/\n\t\tthis.queryAndEnableKittyProtocol();\n\t}\n\n\tprivate handleInitialKeyboardProtocolInput(sequence: string): boolean {\n\t\tif (!this.keyboardProtocolNegotiationPending) return false;\n\t\tconst negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence, true);\n\t\tif (negotiationSequence === \"pending\") return true;\n\t\treturn this.handleKeyboardProtocolNegotiationSequence(negotiationSequence);\n\t}\n\n\tprivate handleLateKeyboardProtocolInput(sequence: string): boolean {\n\t\tif (!this.keyboardProtocolLateResponsePending) return false;\n\t\tconst negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence, false);\n\t\tif (negotiationSequence === \"pending\") {\n\t\t\tthis.scheduleKeyboardProtocolNegotiationBufferFlush();\n\t\t\treturn true;\n\t\t}\n\t\treturn this.handleKeyboardProtocolNegotiationSequence(negotiationSequence);\n\t}\n\n\tprivate handleBufferedInputSequence(sequence: string): void {\n\t\tif (this.handleInitialKeyboardProtocolInput(sequence)) return;\n\t\tif (this.handleLateKeyboardProtocolInput(sequence)) return;\n\t\tthis.forwardInputSequence(sequence);\n\t}\n\n\t/**\n\t * Set up StdinBuffer to split batched input into individual sequences.\n\t * This ensures components receive single events, making matchesKey/isKeyRelease work correctly.\n\t *\n\t * Also watches for Kitty protocol response and enables it when detected.\n\t * This is done here (after stdinBuffer parsing) rather than on raw stdin\n\t * to handle the case where the response arrives split across multiple events.\n\t */\n\tprivate setupStdinBuffer(): void {\n\t\tthis.stdinBuffer = new StdinBuffer({ timeout: 10 });\n\n\t\t// Forward individual sequences to the input handler\n\t\tthis.stdinBuffer.on(\"data\", (sequence) => this.handleBufferedInputSequence(sequence));\n\n\t\t// Re-wrap paste content with bracketed paste markers for existing editor handling\n\t\tthis.stdinBuffer.on(\"paste\", (content) => {\n\t\t\tif (this.inputHandler) {\n\t\t\t\tthis.inputHandler(`\\x1b[200~${content}\\x1b[201~`);\n\t\t\t}\n\t\t});\n\n\t\t// Handler that pipes stdin data through the buffer\n\t\tthis.stdinDataHandler = (data: string) => {\n\t\t\tthis.stdinBuffer!.process(data);\n\t\t};\n\t}\n\n\t/**\n\t * Query terminal for Kitty keyboard protocol support and enable it if available.\n\t *\n\t * Kitty's progressive enhancement detection requires requesting the desired\n\t * flags before querying them. The trailing DA query is a sentinel supported by\n\t * terminals that do not know Kitty keyboard protocol. A short timeout remains\n\t * as a backup for terminals, PTYs, and SSH sessions that delay, split, or drop\n\t * the DA response.\n\t *\n\t * The requested flags are:\n\t * - 1 = disambiguate escape codes\n\t * - 2 = report event types (press/repeat/release)\n\t * - 4 = report alternate keys (shifted key, base layout key)\n\t */\n\tprivate queryAndEnableKittyProtocol(): void {\n\t\tthis.setupStdinBuffer();\n\t\tprocess.stdin.on(\"data\", this.stdinDataHandler!);\n\t\tthis.keyboardProtocolPushed = true;\n\t\tthis.keyboardProtocolNegotiationPending = true;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tprocess.stdout.write(KITTY_KEYBOARD_PROTOCOL_QUERY);\n\t\tthis.keyboardProtocolFallbackTimer = setTimeout(() => {\n\t\t\tthis.keyboardProtocolFallbackTimer = undefined;\n\t\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\t\tif (this.keyboardProtocolNegotiationBuffer === \"\\x1b\") {\n\t\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t\t} else {\n\t\t\t\tthis.scheduleKeyboardProtocolNegotiationBufferFlush();\n\t\t\t}\n\t\t\tthis.enableModifyOtherKeys();\n\t\t}, KITTY_KEYBOARD_PROTOCOL_FALLBACK_TIMEOUT_MS);\n\t}\n\n\tprivate handleKeyboardProtocolNegotiationSequence(\n\t\tnegotiationSequence: KeyboardProtocolNegotiationSequence | undefined,\n\t): boolean {\n\t\tif (!negotiationSequence) return false;\n\t\tif (negotiationSequence.type === \"kitty-flags\") {\n\t\t\tif (negotiationSequence.flags !== 0 && !this._kittyProtocolActive) {\n\t\t\t\tthis._kittyProtocolActive = true;\n\t\t\t\tsetKittyProtocolActive(true);\n\t\t\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\t\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\t\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\t\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\tthis.enableModifyOtherKeys();\n\t\treturn true;\n\t}\n\n\tprivate readKeyboardProtocolNegotiationSequence(\n\t\tsequence: string,\n\t\tallowBareEscapePrefix: boolean,\n\t): KeyboardProtocolNegotiationSequence | \"pending\" | undefined {\n\t\tif (this.keyboardProtocolNegotiationBuffer) {\n\t\t\tconst bufferedSequence = this.keyboardProtocolNegotiationBuffer + sequence;\n\t\t\tconst negotiationSequence = parseKeyboardProtocolNegotiationSequence(bufferedSequence);\n\t\t\tif (negotiationSequence) {\n\t\t\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\t\t\treturn negotiationSequence;\n\t\t\t}\n\t\t\tif (isKeyboardProtocolNegotiationSequencePrefix(bufferedSequence, allowBareEscapePrefix)) {\n\t\t\t\tthis.setKeyboardProtocolNegotiationBuffer(bufferedSequence);\n\t\t\t\treturn \"pending\";\n\t\t\t}\n\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t}\n\n\t\tconst negotiationSequence = parseKeyboardProtocolNegotiationSequence(sequence);\n\t\tif (negotiationSequence) return negotiationSequence;\n\t\tif (isKeyboardProtocolNegotiationSequencePrefix(sequence, allowBareEscapePrefix)) {\n\t\t\tthis.setKeyboardProtocolNegotiationBuffer(sequence);\n\t\t\treturn \"pending\";\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate setKeyboardProtocolNegotiationBuffer(sequence: string): void {\n\t\tthis.clearKeyboardProtocolNegotiationBufferFlushTimer();\n\t\tthis.keyboardProtocolNegotiationBuffer = sequence;\n\t}\n\n\tprivate clearKeyboardProtocolNegotiationBuffer(): void {\n\t\tthis.clearKeyboardProtocolNegotiationBufferFlushTimer();\n\t\tthis.keyboardProtocolNegotiationBuffer = \"\";\n\t}\n\n\tprivate flushKeyboardProtocolNegotiationBufferAsInput(): void {\n\t\tif (!this.keyboardProtocolNegotiationBuffer) return;\n\t\tconst sequence = this.keyboardProtocolNegotiationBuffer;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.forwardInputSequence(sequence);\n\t}\n\n\tprivate scheduleKeyboardProtocolNegotiationBufferFlush(): void {\n\t\tif (!this.keyboardProtocolNegotiationBuffer || this.keyboardProtocolBufferFlushTimer) return;\n\t\tthis.keyboardProtocolBufferFlushTimer = setTimeout(() => {\n\t\t\tthis.keyboardProtocolBufferFlushTimer = undefined;\n\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t}, KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS);\n\t}\n\n\tprivate clearKeyboardProtocolNegotiationBufferFlushTimer(): void {\n\t\tif (!this.keyboardProtocolBufferFlushTimer) return;\n\t\tclearTimeout(this.keyboardProtocolBufferFlushTimer);\n\t\tthis.keyboardProtocolBufferFlushTimer = undefined;\n\t}\n\n\tprivate forwardInputSequence(sequence: string): void {\n\t\tif (!this.inputHandler) return;\n\t\tconst isAppleTerminal = sequence === \"\\r\" && isAppleTerminalSession();\n\t\tconst input = normalizeAppleTerminalInput(\n\t\t\tsequence,\n\t\t\tisAppleTerminal,\n\t\t\tisAppleTerminal && isNativeModifierPressed(\"shift\"),\n\t\t);\n\t\tthis.inputHandler(input);\n\t}\n\n\tprivate enableModifyOtherKeys(): void {\n\t\tif (this._kittyProtocolActive || this._modifyOtherKeysActive) return;\n\t\tprocess.stdout.write(\"\\x1b[>4;2m\");\n\t\tthis._modifyOtherKeysActive = true;\n\t}\n\n\tprivate clearKeyboardProtocolFallbackTimer(): void {\n\t\tif (!this.keyboardProtocolFallbackTimer) return;\n\t\tclearTimeout(this.keyboardProtocolFallbackTimer);\n\t\tthis.keyboardProtocolFallbackTimer = undefined;\n\t}\n\n\t/**\n\t * On Windows, add ENABLE_VIRTUAL_TERMINAL_INPUT (0x0200) to the stdin\n\t * console handle so the terminal sends VT sequences for modified keys\n\t * (e.g. \\x1b[Z for Shift+Tab). Without this, libuv's ReadConsoleInputW\n\t * discards modifier state and Shift+Tab arrives as plain \\t.\n\t */\n\tprivate enableWindowsVTInput(): void {\n\t\tif (process.platform !== \"win32\") return;\n\t\ttry {\n\t\t\tconst arch = process.arch;\n\t\t\tif (arch !== \"x64\" && arch !== \"arm64\") return;\n\n\t\t\t// Dynamic require so non-Windows and bundled/browser paths never load the\n\t\t\t// native helper. In the npm package native/ is next to dist/; in compiled\n\t\t\t// binary archives native/ is copied next to the executable.\n\t\t\tconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\t\t\tconst nativePath = path.join(\"native\", \"win32\", \"prebuilds\", `win32-${arch}`, \"win32-console-mode.node\");\n\t\t\tconst candidates = [\n\t\t\t\tpath.join(moduleDir, \"..\", nativePath),\n\t\t\t\tpath.join(moduleDir, nativePath),\n\t\t\t\tpath.join(path.dirname(process.execPath), nativePath),\n\t\t\t];\n\t\t\tfor (const modulePath of candidates) {\n\t\t\t\ttry {\n\t\t\t\t\tconst helper = cjsRequire(modulePath) as { enableVirtualTerminalInput?: () => boolean };\n\t\t\t\t\thelper.enableVirtualTerminalInput?.();\n\t\t\t\t\treturn;\n\t\t\t\t} catch {\n\t\t\t\t\t// Try the next possible packaging location.\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Native helper not available — Shift+Tab won't be distinguishable from Tab.\n\t\t}\n\t}\n\n\tasync drainInput(maxMs = 1000, idleMs = 50): Promise<void> {\n\t\tconst shouldDisableKittyProtocol =\n\t\t\tthis.keyboardProtocolPushed || this._kittyProtocolActive || this.keyboardProtocolNegotiationPending;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\tif (shouldDisableKittyProtocol) {\n\t\t\t// Disable Kitty keyboard protocol first so any late key releases\n\t\t\t// do not generate new Kitty escape sequences.\n\t\t\tprocess.stdout.write(\"\\x1b[<u\");\n\t\t\tthis.keyboardProtocolPushed = false;\n\t\t\tthis._kittyProtocolActive = false;\n\t\t\tsetKittyProtocolActive(false);\n\t\t}\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tif (this._modifyOtherKeysActive) {\n\t\t\tprocess.stdout.write(\"\\x1b[>4;0m\");\n\t\t\tthis._modifyOtherKeysActive = false;\n\t\t}\n\n\t\tconst previousHandler = this.inputHandler;\n\t\tthis.inputHandler = undefined;\n\n\t\tlet lastDataTime = Date.now();\n\t\tconst onData = () => {\n\t\t\tlastDataTime = Date.now();\n\t\t};\n\n\t\tprocess.stdin.on(\"data\", onData);\n\t\tconst endTime = Date.now() + maxMs;\n\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst now = Date.now();\n\t\t\t\tconst timeLeft = endTime - now;\n\t\t\t\tif (timeLeft <= 0) break;\n\t\t\t\tif (now - lastDataTime >= idleMs) break;\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, Math.min(idleMs, timeLeft)));\n\t\t\t}\n\t\t} finally {\n\t\t\tprocess.stdin.removeListener(\"data\", onData);\n\t\t\tthis.inputHandler = previousHandler;\n\t\t}\n\t}\n\n\tstop(): void {\n\t\tthis.started = false;\n\t\tif (this.clearProgressInterval()) {\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE);\n\t\t}\n\n\t\t// Disable bracketed paste mode\n\t\tprocess.stdout.write(\"\\x1b[?2004l\");\n\n\t\tconst shouldDisableKittyProtocol =\n\t\t\tthis.keyboardProtocolPushed || this._kittyProtocolActive || this.keyboardProtocolNegotiationPending;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\n\t\t// Disable Kitty keyboard protocol if not already done by drainInput()\n\t\tif (shouldDisableKittyProtocol) {\n\t\t\tprocess.stdout.write(\"\\x1b[<u\");\n\t\t\tthis.keyboardProtocolPushed = false;\n\t\t\tthis._kittyProtocolActive = false;\n\t\t\tsetKittyProtocolActive(false);\n\t\t}\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tif (this._modifyOtherKeysActive) {\n\t\t\tprocess.stdout.write(\"\\x1b[>4;0m\");\n\t\t\tthis._modifyOtherKeysActive = false;\n\t\t}\n\n\t\t// Clean up StdinBuffer\n\t\tif (this.stdinBuffer) {\n\t\t\tthis.stdinBuffer.destroy();\n\t\t\tthis.stdinBuffer = undefined;\n\t\t}\n\n\t\t// Remove event handlers\n\t\tif (this.stdinDataHandler) {\n\t\t\tprocess.stdin.removeListener(\"data\", this.stdinDataHandler);\n\t\t\tthis.stdinDataHandler = undefined;\n\t\t}\n\t\tthis.inputHandler = undefined;\n\t\tif (this.resizeHandler) {\n\t\t\tprocess.stdout.removeListener(\"resize\", this.resizeHandler);\n\t\t\tthis.resizeHandler = undefined;\n\t\t}\n\n\t\t// Pause stdin to prevent any buffered input (e.g., Ctrl+D) from being\n\t\t// re-interpreted after raw mode is disabled. This fixes a race condition\n\t\t// where Ctrl+D could close the parent shell over SSH.\n\t\tprocess.stdin.pause();\n\n\t\t// Restore raw mode state\n\t\tif (process.stdin.setRawMode) {\n\t\t\tprocess.stdin.setRawMode(this.wasRaw);\n\t\t}\n\t}\n\n\twrite(data: string): void {\n\t\tprocess.stdout.write(data);\n\t\tif (this.writeLogPath) {\n\t\t\ttry {\n\t\t\t\tfs.appendFileSync(this.writeLogPath, data, { encoding: \"utf8\" });\n\t\t\t} catch {\n\t\t\t\t// Ignore logging errors\n\t\t\t}\n\t\t}\n\t}\n\n\tget columns(): number {\n\t\treturn process.stdout.columns || Number(process.env.COLUMNS) || 80;\n\t}\n\n\tget rows(): number {\n\t\treturn process.stdout.rows || Number(process.env.LINES) || 24;\n\t}\n\n\tmoveBy(lines: number): void {\n\t\tif (lines > 0) {\n\t\t\t// Move down\n\t\t\tprocess.stdout.write(`\\x1b[${lines}B`);\n\t\t} else if (lines < 0) {\n\t\t\t// Move up\n\t\t\tprocess.stdout.write(`\\x1b[${-lines}A`);\n\t\t}\n\t\t// lines === 0: no movement\n\t}\n\n\thideCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[?25l\");\n\t}\n\n\tshowCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[?25h\");\n\t}\n\n\tclearLine(): void {\n\t\tprocess.stdout.write(\"\\x1b[K\");\n\t}\n\n\tclearFromCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[J\");\n\t}\n\n\tclearScreen(): void {\n\t\tprocess.stdout.write(\"\\x1b[2J\\x1b[H\"); // Clear screen and move to home (1,1)\n\t}\n\n\tsetTitle(title: string): void {\n\t\t// OSC 0;title BEL - set terminal window title\n\t\tprocess.stdout.write(`\\x1b]0;${sanitizeTerminalControlPayload(title)}\\x07`);\n\t}\n\n\tsetProgress(active: boolean): void {\n\t\tif (active) {\n\t\t\t// OSC 9;4;3 - indeterminate progress\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE);\n\t\t\tif (!this.progressInterval) {\n\t\t\t\tthis.progressInterval = setInterval(() => {\n\t\t\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE);\n\t\t\t\t}, TERMINAL_PROGRESS_KEEPALIVE_MS);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.clearProgressInterval();\n\t\t\t// OSC 9;4;0 - clear progress\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE);\n\t\t}\n\t}\n\n\tprivate clearProgressInterval(): boolean {\n\t\tif (!this.progressInterval) return false;\n\t\tclearInterval(this.progressInterval);\n\t\tthis.progressInterval = undefined;\n\t\treturn true;\n\t}\n}\n"]}
1
+ {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../src/terminal.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { setKittyProtocolActive } from \"./keys.ts\";\nimport { isNativeModifierPressed } from \"./native-modifiers.ts\";\nimport { StdinBuffer } from \"./stdin-buffer.ts\";\nimport { sanitizeTerminalControlPayload } from \"./terminal-control.ts\";\n\nconst cjsRequire = createRequire(import.meta.url);\n\nconst TERMINAL_PROGRESS_KEEPALIVE_MS = 1000;\nconst TERMINAL_PROGRESS_ACTIVE_SEQUENCE = \"\\x1b]9;4;3\\x07\";\nconst TERMINAL_PROGRESS_CLEAR_SEQUENCE = \"\\x1b]9;4;0\\x07\";\nconst APPLE_TERMINAL_SHIFT_ENTER_SEQUENCE = \"\\x1b[13;2u\";\nconst DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS = 7;\nconst KITTY_KEYBOARD_PROTOCOL_FALLBACK_TIMEOUT_MS = 150;\nconst KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS = 150;\nconst KITTY_KEYBOARD_PROTOCOL_QUERY = `\\x1b[>${DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS}u\\x1b[?u\\x1b[c`;\n\nexport type KeyboardProtocolNegotiationSequence =\n\t| { type: \"kitty-flags\"; flags: number }\n\t| { type: \"device-attributes\" };\n\nexport function parseKeyboardProtocolNegotiationSequence(\n\tsequence: string,\n): KeyboardProtocolNegotiationSequence | undefined {\n\tconst kittyFlags = sequence.match(/^\\x1b\\[\\?(\\d+)u$/);\n\tif (kittyFlags) {\n\t\treturn { type: \"kitty-flags\", flags: Number.parseInt(kittyFlags[1]!, 10) };\n\t}\n\tif (/^\\x1b\\[\\?[\\d;]*c$/.test(sequence)) {\n\t\treturn { type: \"device-attributes\" };\n\t}\n\treturn undefined;\n}\n\nfunction isKeyboardProtocolNegotiationSequencePrefix(sequence: string, allowBareEscapePrefix: boolean): boolean {\n\treturn (allowBareEscapePrefix && sequence === \"\\x1b\") || sequence === \"\\x1b[\" || /^\\x1b\\[\\?[\\d;]*$/.test(sequence);\n}\n\nexport function isAppleTerminalSession(): boolean {\n\treturn process.platform === \"darwin\" && process.env.TERM_PROGRAM === \"Apple_Terminal\";\n}\n\nexport function normalizeAppleTerminalInput(data: string, isAppleTerminal: boolean, isShiftPressed: boolean): string {\n\tif (isAppleTerminal && data === \"\\r\" && isShiftPressed) return APPLE_TERMINAL_SHIFT_ENTER_SEQUENCE;\n\treturn data;\n}\n\n/**\n * Minimal terminal interface for TUI\n */\nexport interface Terminal {\n\t// Start the terminal with input and resize handlers\n\tstart(onInput: (data: string) => void, onResize: () => void): void;\n\n\t// Stop the terminal and restore state\n\tstop(): void;\n\n\t/**\n\t * Drain stdin before exiting to prevent Kitty key release events from\n\t * leaking to the parent shell over slow SSH connections.\n\t * @param maxMs - Maximum time to drain (default: 1000ms)\n\t * @param idleMs - Exit early if no input arrives within this time (default: 50ms)\n\t */\n\tdrainInput(maxMs?: number, idleMs?: number): Promise<void>;\n\n\t// Write output to terminal\n\twrite(data: string): void;\n\n\t// Get terminal dimensions\n\tget columns(): number;\n\tget rows(): number;\n\n\t// Whether Kitty keyboard protocol is active\n\tget kittyProtocolActive(): boolean;\n\n\t// Cursor positioning (relative to current position)\n\tmoveBy(lines: number): void; // Move cursor up (negative) or down (positive) by N lines\n\n\t// Cursor visibility\n\thideCursor(): void; // Hide the cursor\n\tshowCursor(): void; // Show the cursor\n\n\t// Clear operations\n\tclearLine(): void; // Clear current line\n\tclearFromCursor(): void; // Clear from cursor to end of screen\n\tclearScreen(): void; // Clear entire screen and move cursor to (0,0)\n\n\t// Title operations\n\tsetTitle(title: string): void; // Set terminal window title\n\n\t// Progress indicator (OSC 9;4)\n\tsetProgress(active: boolean): void;\n}\n\n/**\n * Real terminal using process.stdin/stdout\n */\nexport class ProcessTerminal implements Terminal {\n\tprivate wasRaw = false;\n\tprivate started = false;\n\tprivate inputHandler?: (data: string) => void;\n\tprivate resizeHandler?: () => void;\n\tprivate _kittyProtocolActive = false;\n\tprivate _modifyOtherKeysActive = false;\n\tprivate keyboardProtocolPushed = false;\n\tprivate keyboardProtocolNegotiationPending = false;\n\tprivate keyboardProtocolLateResponsePending = false;\n\tprivate keyboardProtocolNegotiationBuffer = \"\";\n\tprivate keyboardProtocolFallbackTimer?: ReturnType<typeof setTimeout>;\n\tprivate keyboardProtocolBufferFlushTimer?: ReturnType<typeof setTimeout>;\n\tprivate stdinBuffer?: StdinBuffer;\n\tprivate stdinDataHandler?: (data: string) => void;\n\tprivate progressInterval?: ReturnType<typeof setInterval>;\n\tprivate writeLogPath = (() => {\n\t\tconst env = process.env.GRIP_TUI_WRITE_LOG || \"\";\n\t\tif (!env) return \"\";\n\t\ttry {\n\t\t\tif (fs.statSync(env).isDirectory()) {\n\t\t\t\tconst now = new Date();\n\t\t\t\tconst ts = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, \"0\")}-${String(now.getDate()).padStart(2, \"0\")}_${String(now.getHours()).padStart(2, \"0\")}-${String(now.getMinutes()).padStart(2, \"0\")}-${String(now.getSeconds()).padStart(2, \"0\")}`;\n\t\t\t\treturn path.join(env, `tui-${ts}-${process.pid}.log`);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Not an existing directory - use as-is (file path)\n\t\t}\n\t\treturn env;\n\t})();\n\n\tget kittyProtocolActive(): boolean {\n\t\treturn this._kittyProtocolActive;\n\t}\n\n\tstart(onInput: (data: string) => void, onResize: () => void): void {\n\t\tif (this.started) {\n\t\t\tthis.inputHandler = onInput;\n\t\t\tif (this.resizeHandler !== onResize) {\n\t\t\t\tif (this.resizeHandler) process.stdout.removeListener(\"resize\", this.resizeHandler);\n\t\t\t\tthis.resizeHandler = onResize;\n\t\t\t\tprocess.stdout.on(\"resize\", onResize);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis.started = true;\n\t\tthis.inputHandler = onInput;\n\t\tthis.resizeHandler = onResize;\n\t\t// Save previous state and enable raw mode\n\t\tthis.wasRaw = process.stdin.isRaw || false;\n\t\tif (process.stdin.setRawMode) {\n\t\t\tprocess.stdin.setRawMode(true);\n\t\t}\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\t\tprocess.stdin.resume();\n\n\t\t// Enable bracketed paste mode - terminal will wrap pastes in \\x1b[200~ ... \\x1b[201~\n\t\tprocess.stdout.write(\"\\x1b[?2004h\");\n\n\t\t// Set up resize handler immediately\n\t\tprocess.stdout.on(\"resize\", this.resizeHandler);\n\n\t\t// Refresh terminal dimensions - they may be stale after suspend/resume\n\t\t// (SIGWINCH is lost while process is stopped). Unix only.\n\t\tif (process.platform !== \"win32\") {\n\t\t\tprocess.kill(process.pid, \"SIGWINCH\");\n\t\t}\n\n\t\t// On Windows, enable ENABLE_VIRTUAL_TERMINAL_INPUT so the console sends\n\t\t// VT escape sequences (e.g. \\x1b[Z for Shift+Tab) instead of raw console\n\t\t// events that lose modifier information. Must run AFTER setRawMode(true)\n\t\t// since that resets console mode flags.\n\t\tthis.enableWindowsVTInput();\n\n\t\t// Query and enable Kitty keyboard protocol\n\t\t// The query handler intercepts input temporarily, then installs the user's handler\n\t\t// See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/\n\t\tthis.queryAndEnableKittyProtocol();\n\t}\n\n\tprivate handleInitialKeyboardProtocolInput(sequence: string): boolean {\n\t\tif (!this.keyboardProtocolNegotiationPending) return false;\n\t\tconst negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence, true);\n\t\tif (negotiationSequence === \"pending\") return true;\n\t\treturn this.handleKeyboardProtocolNegotiationSequence(negotiationSequence);\n\t}\n\n\tprivate handleLateKeyboardProtocolInput(sequence: string): boolean {\n\t\tif (!this.keyboardProtocolLateResponsePending) return false;\n\t\tconst negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence, false);\n\t\tif (negotiationSequence === \"pending\") {\n\t\t\tthis.scheduleKeyboardProtocolNegotiationBufferFlush();\n\t\t\treturn true;\n\t\t}\n\t\treturn this.handleKeyboardProtocolNegotiationSequence(negotiationSequence);\n\t}\n\n\tprivate handleBufferedInputSequence(sequence: string): void {\n\t\tif (this.handleInitialKeyboardProtocolInput(sequence)) return;\n\t\tif (this.handleLateKeyboardProtocolInput(sequence)) return;\n\t\tthis.forwardInputSequence(sequence);\n\t}\n\n\t/**\n\t * Set up StdinBuffer to split batched input into individual sequences.\n\t * This ensures components receive single events, making matchesKey/isKeyRelease work correctly.\n\t *\n\t * Also watches for Kitty protocol response and enables it when detected.\n\t * This is done here (after stdinBuffer parsing) rather than on raw stdin\n\t * to handle the case where the response arrives split across multiple events.\n\t */\n\tprivate setupStdinBuffer(): void {\n\t\tthis.stdinBuffer = new StdinBuffer({ timeout: 10 });\n\n\t\t// Forward individual sequences to the input handler\n\t\tthis.stdinBuffer.on(\"data\", (sequence) => this.handleBufferedInputSequence(sequence));\n\n\t\t// Re-wrap paste content with bracketed paste markers for existing editor handling\n\t\tthis.stdinBuffer.on(\"paste\", (content) => {\n\t\t\tif (this.inputHandler) {\n\t\t\t\tthis.inputHandler(`\\x1b[200~${content}\\x1b[201~`);\n\t\t\t}\n\t\t});\n\n\t\t// Handler that pipes stdin data through the buffer\n\t\tthis.stdinDataHandler = (data: string) => {\n\t\t\tthis.stdinBuffer!.process(data);\n\t\t};\n\t}\n\n\t/**\n\t * Query terminal for Kitty keyboard protocol support and enable it if available.\n\t *\n\t * Kitty's progressive enhancement detection requires requesting the desired\n\t * flags before querying them. The trailing DA query is a sentinel supported by\n\t * terminals that do not know Kitty keyboard protocol. A short timeout remains\n\t * as a backup for terminals, PTYs, and SSH sessions that delay, split, or drop\n\t * the DA response.\n\t *\n\t * The requested flags are:\n\t * - 1 = disambiguate escape codes\n\t * - 2 = report event types (press/repeat/release)\n\t * - 4 = report alternate keys (shifted key, base layout key)\n\t */\n\tprivate queryAndEnableKittyProtocol(): void {\n\t\tthis.setupStdinBuffer();\n\t\tprocess.stdin.on(\"data\", this.stdinDataHandler!);\n\t\tthis.keyboardProtocolPushed = true;\n\t\tthis.keyboardProtocolNegotiationPending = true;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tprocess.stdout.write(KITTY_KEYBOARD_PROTOCOL_QUERY);\n\t\tthis.keyboardProtocolFallbackTimer = setTimeout(() => {\n\t\t\tthis.keyboardProtocolFallbackTimer = undefined;\n\t\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\t\tif (this.keyboardProtocolNegotiationBuffer === \"\\x1b\") {\n\t\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t\t} else {\n\t\t\t\tthis.scheduleKeyboardProtocolNegotiationBufferFlush();\n\t\t\t}\n\t\t\tthis.enableModifyOtherKeys();\n\t\t}, KITTY_KEYBOARD_PROTOCOL_FALLBACK_TIMEOUT_MS);\n\t}\n\n\tprivate handleKeyboardProtocolNegotiationSequence(\n\t\tnegotiationSequence: KeyboardProtocolNegotiationSequence | undefined,\n\t): boolean {\n\t\tif (!negotiationSequence) return false;\n\t\tif (negotiationSequence.type === \"kitty-flags\") {\n\t\t\tif (negotiationSequence.flags !== 0 && !this._kittyProtocolActive) {\n\t\t\t\tthis._kittyProtocolActive = true;\n\t\t\t\tsetKittyProtocolActive(true);\n\t\t\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\t\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\t\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\t\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\tthis.enableModifyOtherKeys();\n\t\treturn true;\n\t}\n\n\tprivate readKeyboardProtocolNegotiationSequence(\n\t\tsequence: string,\n\t\tallowBareEscapePrefix: boolean,\n\t): KeyboardProtocolNegotiationSequence | \"pending\" | undefined {\n\t\tif (this.keyboardProtocolNegotiationBuffer) {\n\t\t\tconst bufferedSequence = this.keyboardProtocolNegotiationBuffer + sequence;\n\t\t\tconst negotiationSequence = parseKeyboardProtocolNegotiationSequence(bufferedSequence);\n\t\t\tif (negotiationSequence) {\n\t\t\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\t\t\treturn negotiationSequence;\n\t\t\t}\n\t\t\tif (isKeyboardProtocolNegotiationSequencePrefix(bufferedSequence, allowBareEscapePrefix)) {\n\t\t\t\tthis.setKeyboardProtocolNegotiationBuffer(bufferedSequence);\n\t\t\t\treturn \"pending\";\n\t\t\t}\n\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t}\n\n\t\tconst negotiationSequence = parseKeyboardProtocolNegotiationSequence(sequence);\n\t\tif (negotiationSequence) return negotiationSequence;\n\t\tif (isKeyboardProtocolNegotiationSequencePrefix(sequence, allowBareEscapePrefix)) {\n\t\t\tthis.setKeyboardProtocolNegotiationBuffer(sequence);\n\t\t\treturn \"pending\";\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate setKeyboardProtocolNegotiationBuffer(sequence: string): void {\n\t\tthis.clearKeyboardProtocolNegotiationBufferFlushTimer();\n\t\tthis.keyboardProtocolNegotiationBuffer = sequence;\n\t}\n\n\tprivate clearKeyboardProtocolNegotiationBuffer(): void {\n\t\tthis.clearKeyboardProtocolNegotiationBufferFlushTimer();\n\t\tthis.keyboardProtocolNegotiationBuffer = \"\";\n\t}\n\n\tprivate flushKeyboardProtocolNegotiationBufferAsInput(): void {\n\t\tif (!this.keyboardProtocolNegotiationBuffer) return;\n\t\tconst sequence = this.keyboardProtocolNegotiationBuffer;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.forwardInputSequence(sequence);\n\t}\n\n\tprivate scheduleKeyboardProtocolNegotiationBufferFlush(): void {\n\t\tif (!this.keyboardProtocolNegotiationBuffer || this.keyboardProtocolBufferFlushTimer) return;\n\t\tthis.keyboardProtocolBufferFlushTimer = setTimeout(() => {\n\t\t\tthis.keyboardProtocolBufferFlushTimer = undefined;\n\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t}, KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS);\n\t}\n\n\tprivate clearKeyboardProtocolNegotiationBufferFlushTimer(): void {\n\t\tif (!this.keyboardProtocolBufferFlushTimer) return;\n\t\tclearTimeout(this.keyboardProtocolBufferFlushTimer);\n\t\tthis.keyboardProtocolBufferFlushTimer = undefined;\n\t}\n\n\tprivate forwardInputSequence(sequence: string): void {\n\t\tif (!this.inputHandler) return;\n\t\tconst isAppleTerminal = sequence === \"\\r\" && isAppleTerminalSession();\n\t\tconst input = normalizeAppleTerminalInput(\n\t\t\tsequence,\n\t\t\tisAppleTerminal,\n\t\t\tisAppleTerminal && isNativeModifierPressed(\"shift\"),\n\t\t);\n\t\tthis.inputHandler(input);\n\t}\n\n\tprivate enableModifyOtherKeys(): void {\n\t\tif (this._kittyProtocolActive || this._modifyOtherKeysActive) return;\n\t\tprocess.stdout.write(\"\\x1b[>4;2m\");\n\t\tthis._modifyOtherKeysActive = true;\n\t}\n\n\tprivate clearKeyboardProtocolFallbackTimer(): void {\n\t\tif (!this.keyboardProtocolFallbackTimer) return;\n\t\tclearTimeout(this.keyboardProtocolFallbackTimer);\n\t\tthis.keyboardProtocolFallbackTimer = undefined;\n\t}\n\n\t/**\n\t * On Windows, add ENABLE_VIRTUAL_TERMINAL_INPUT (0x0200) to the stdin\n\t * console handle so the terminal sends VT sequences for modified keys\n\t * (e.g. \\x1b[Z for Shift+Tab). Without this, libuv's ReadConsoleInputW\n\t * discards modifier state and Shift+Tab arrives as plain \\t.\n\t */\n\tprivate enableWindowsVTInput(): void {\n\t\tif (process.platform !== \"win32\") return;\n\t\ttry {\n\t\t\tconst arch = process.arch;\n\t\t\tif (arch !== \"x64\" && arch !== \"arm64\") return;\n\n\t\t\t// Dynamic require so non-Windows and bundled/browser paths never load the\n\t\t\t// native helper. In the npm package native/ is next to dist/; in compiled\n\t\t\t// binary archives native/ is copied next to the executable.\n\t\t\tconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\t\t\tconst nativePath = path.join(\"native\", \"win32\", \"prebuilds\", `win32-${arch}`, \"win32-console-mode.node\");\n\t\t\tconst candidates = [\n\t\t\t\tpath.join(moduleDir, \"..\", nativePath),\n\t\t\t\tpath.join(moduleDir, nativePath),\n\t\t\t\tpath.join(process.env.GRIP_EMBEDDED_ASSET_DIR || path.dirname(process.execPath), nativePath),\n\t\t\t];\n\t\t\tfor (const modulePath of candidates) {\n\t\t\t\ttry {\n\t\t\t\t\tconst helper = cjsRequire(modulePath) as { enableVirtualTerminalInput?: () => boolean };\n\t\t\t\t\thelper.enableVirtualTerminalInput?.();\n\t\t\t\t\treturn;\n\t\t\t\t} catch {\n\t\t\t\t\t// Try the next possible packaging location.\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Native helper not available — Shift+Tab won't be distinguishable from Tab.\n\t\t}\n\t}\n\n\tasync drainInput(maxMs = 1000, idleMs = 50): Promise<void> {\n\t\tconst shouldDisableKittyProtocol =\n\t\t\tthis.keyboardProtocolPushed || this._kittyProtocolActive || this.keyboardProtocolNegotiationPending;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\tif (shouldDisableKittyProtocol) {\n\t\t\t// Disable Kitty keyboard protocol first so any late key releases\n\t\t\t// do not generate new Kitty escape sequences.\n\t\t\tprocess.stdout.write(\"\\x1b[<u\");\n\t\t\tthis.keyboardProtocolPushed = false;\n\t\t\tthis._kittyProtocolActive = false;\n\t\t\tsetKittyProtocolActive(false);\n\t\t}\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tif (this._modifyOtherKeysActive) {\n\t\t\tprocess.stdout.write(\"\\x1b[>4;0m\");\n\t\t\tthis._modifyOtherKeysActive = false;\n\t\t}\n\n\t\tconst previousHandler = this.inputHandler;\n\t\tthis.inputHandler = undefined;\n\n\t\tlet lastDataTime = Date.now();\n\t\tconst onData = () => {\n\t\t\tlastDataTime = Date.now();\n\t\t};\n\n\t\tprocess.stdin.on(\"data\", onData);\n\t\tconst endTime = Date.now() + maxMs;\n\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst now = Date.now();\n\t\t\t\tconst timeLeft = endTime - now;\n\t\t\t\tif (timeLeft <= 0) break;\n\t\t\t\tif (now - lastDataTime >= idleMs) break;\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, Math.min(idleMs, timeLeft)));\n\t\t\t}\n\t\t} finally {\n\t\t\tprocess.stdin.removeListener(\"data\", onData);\n\t\t\tthis.inputHandler = previousHandler;\n\t\t}\n\t}\n\n\tstop(): void {\n\t\tthis.started = false;\n\t\tif (this.clearProgressInterval()) {\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE);\n\t\t}\n\n\t\t// Disable bracketed paste mode\n\t\tprocess.stdout.write(\"\\x1b[?2004l\");\n\n\t\tconst shouldDisableKittyProtocol =\n\t\t\tthis.keyboardProtocolPushed || this._kittyProtocolActive || this.keyboardProtocolNegotiationPending;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\n\t\t// Disable Kitty keyboard protocol if not already done by drainInput()\n\t\tif (shouldDisableKittyProtocol) {\n\t\t\tprocess.stdout.write(\"\\x1b[<u\");\n\t\t\tthis.keyboardProtocolPushed = false;\n\t\t\tthis._kittyProtocolActive = false;\n\t\t\tsetKittyProtocolActive(false);\n\t\t}\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tif (this._modifyOtherKeysActive) {\n\t\t\tprocess.stdout.write(\"\\x1b[>4;0m\");\n\t\t\tthis._modifyOtherKeysActive = false;\n\t\t}\n\n\t\t// Clean up StdinBuffer\n\t\tif (this.stdinBuffer) {\n\t\t\tthis.stdinBuffer.destroy();\n\t\t\tthis.stdinBuffer = undefined;\n\t\t}\n\n\t\t// Remove event handlers\n\t\tif (this.stdinDataHandler) {\n\t\t\tprocess.stdin.removeListener(\"data\", this.stdinDataHandler);\n\t\t\tthis.stdinDataHandler = undefined;\n\t\t}\n\t\tthis.inputHandler = undefined;\n\t\tif (this.resizeHandler) {\n\t\t\tprocess.stdout.removeListener(\"resize\", this.resizeHandler);\n\t\t\tthis.resizeHandler = undefined;\n\t\t}\n\n\t\t// Pause stdin to prevent any buffered input (e.g., Ctrl+D) from being\n\t\t// re-interpreted after raw mode is disabled. This fixes a race condition\n\t\t// where Ctrl+D could close the parent shell over SSH.\n\t\tprocess.stdin.pause();\n\n\t\t// Restore raw mode state\n\t\tif (process.stdin.setRawMode) {\n\t\t\tprocess.stdin.setRawMode(this.wasRaw);\n\t\t}\n\t}\n\n\twrite(data: string): void {\n\t\tprocess.stdout.write(data);\n\t\tif (this.writeLogPath) {\n\t\t\ttry {\n\t\t\t\tfs.appendFileSync(this.writeLogPath, data, { encoding: \"utf8\" });\n\t\t\t} catch {\n\t\t\t\t// Ignore logging errors\n\t\t\t}\n\t\t}\n\t}\n\n\tget columns(): number {\n\t\treturn process.stdout.columns || Number(process.env.COLUMNS) || 80;\n\t}\n\n\tget rows(): number {\n\t\treturn process.stdout.rows || Number(process.env.LINES) || 24;\n\t}\n\n\tmoveBy(lines: number): void {\n\t\tif (lines > 0) {\n\t\t\t// Move down\n\t\t\tprocess.stdout.write(`\\x1b[${lines}B`);\n\t\t} else if (lines < 0) {\n\t\t\t// Move up\n\t\t\tprocess.stdout.write(`\\x1b[${-lines}A`);\n\t\t}\n\t\t// lines === 0: no movement\n\t}\n\n\thideCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[?25l\");\n\t}\n\n\tshowCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[?25h\");\n\t}\n\n\tclearLine(): void {\n\t\tprocess.stdout.write(\"\\x1b[K\");\n\t}\n\n\tclearFromCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[J\");\n\t}\n\n\tclearScreen(): void {\n\t\tprocess.stdout.write(\"\\x1b[2J\\x1b[H\"); // Clear screen and move to home (1,1)\n\t}\n\n\tsetTitle(title: string): void {\n\t\t// OSC 0;title BEL - set terminal window title\n\t\tprocess.stdout.write(`\\x1b]0;${sanitizeTerminalControlPayload(title)}\\x07`);\n\t}\n\n\tsetProgress(active: boolean): void {\n\t\tif (active) {\n\t\t\t// OSC 9;4;3 - indeterminate progress\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE);\n\t\t\tif (!this.progressInterval) {\n\t\t\t\tthis.progressInterval = setInterval(() => {\n\t\t\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE);\n\t\t\t\t}, TERMINAL_PROGRESS_KEEPALIVE_MS);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.clearProgressInterval();\n\t\t\t// OSC 9;4;0 - clear progress\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE);\n\t\t}\n\t}\n\n\tprivate clearProgressInterval(): boolean {\n\t\tif (!this.progressInterval) return false;\n\t\tclearInterval(this.progressInterval);\n\t\tthis.progressInterval = undefined;\n\t\treturn true;\n\t}\n}\n"]}
package/dist/terminal.js CHANGED
@@ -310,7 +310,7 @@ export class ProcessTerminal {
310
310
  const candidates = [
311
311
  path.join(moduleDir, "..", nativePath),
312
312
  path.join(moduleDir, nativePath),
313
- path.join(path.dirname(process.execPath), nativePath),
313
+ path.join(process.env.GRIP_EMBEDDED_ASSET_DIR || path.dirname(process.execPath), nativePath),
314
314
  ];
315
315
  for (const modulePath of candidates) {
316
316
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../src/terminal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,8BAA8B,EAAE,MAAM,uBAAuB,CAAC;AAEvE,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AAElD,MAAM,8BAA8B,GAAG,IAAI,CAAC;AAC5C,MAAM,iCAAiC,GAAG,gBAAgB,CAAC;AAC3D,MAAM,gCAAgC,GAAG,gBAAgB,CAAC;AAC1D,MAAM,mCAAmC,GAAG,YAAY,CAAC;AACzD,MAAM,qCAAqC,GAAG,CAAC,CAAC;AAChD,MAAM,2CAA2C,GAAG,GAAG,CAAC;AACxD,MAAM,8CAA8C,GAAG,GAAG,CAAC;AAC3D,MAAM,6BAA6B,GAAG,SAAS,qCAAqC,gBAAgB,CAAC;AAMrG,MAAM,UAAU,wCAAwC,CACvD,QAAgB,EACkC;IAClD,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACtD,IAAI,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,EAAE,CAAC;IAC5E,CAAC;IACD,IAAI,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxC,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC;IACtC,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,SAAS,2CAA2C,CAAC,QAAgB,EAAE,qBAA8B,EAAW;IAC/G,OAAO,CAAC,qBAAqB,IAAI,QAAQ,KAAK,MAAM,CAAC,IAAI,QAAQ,KAAK,OAAO,IAAI,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAAA,CACnH;AAED,MAAM,UAAU,sBAAsB,GAAY;IACjD,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,gBAAgB,CAAC;AAAA,CACtF;AAED,MAAM,UAAU,2BAA2B,CAAC,IAAY,EAAE,eAAwB,EAAE,cAAuB,EAAU;IACpH,IAAI,eAAe,IAAI,IAAI,KAAK,IAAI,IAAI,cAAc;QAAE,OAAO,mCAAmC,CAAC;IACnG,OAAO,IAAI,CAAC;AAAA,CACZ;AAiDD;;GAEG;AACH,MAAM,OAAO,eAAe;IACnB,MAAM,GAAG,KAAK,CAAC;IACf,OAAO,GAAG,KAAK,CAAC;IAChB,YAAY,CAA0B;IACtC,aAAa,CAAc;IAC3B,oBAAoB,GAAG,KAAK,CAAC;IAC7B,sBAAsB,GAAG,KAAK,CAAC;IAC/B,sBAAsB,GAAG,KAAK,CAAC;IAC/B,kCAAkC,GAAG,KAAK,CAAC;IAC3C,mCAAmC,GAAG,KAAK,CAAC;IAC5C,iCAAiC,GAAG,EAAE,CAAC;IACvC,6BAA6B,CAAiC;IAC9D,gCAAgC,CAAiC;IACjE,WAAW,CAAe;IAC1B,gBAAgB,CAA0B;IAC1C,gBAAgB,CAAkC;IAClD,YAAY,GAAG,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,EAAE,CAAC;QACjD,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,CAAC;QACpB,IAAI,CAAC;YACJ,IAAI,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;gBACpC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC,WAAW,EAAE,IAAI,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;gBAChQ,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;YACvD,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,oDAAoD;QACrD,CAAC;QACD,OAAO,GAAG,CAAC;IAAA,CACX,CAAC,EAAE,CAAC;IAEL,IAAI,mBAAmB,GAAY;QAClC,OAAO,IAAI,CAAC,oBAAoB,CAAC;IAAA,CACjC;IAED,KAAK,CAAC,OAA+B,EAAE,QAAoB,EAAQ;QAClE,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC;YAC5B,IAAI,IAAI,CAAC,aAAa,KAAK,QAAQ,EAAE,CAAC;gBACrC,IAAI,IAAI,CAAC,aAAa;oBAAE,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;gBACpF,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;gBAC9B,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACvC,CAAC;YACD,OAAO;QACR,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC;QAC5B,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;QAC9B,0CAA0C;QAC1C,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC;QAC3C,IAAI,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;YAC9B,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAEvB,qFAAqF;QACrF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAEpC,oCAAoC;QACpC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QAEhD,uEAAuE;QACvE,0DAA0D;QAC1D,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QACvC,CAAC;QAED,wEAAwE;QACxE,yEAAyE;QACzE,yEAAyE;QACzE,wCAAwC;QACxC,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAE5B,2CAA2C;QAC3C,mFAAmF;QACnF,0DAA0D;QAC1D,IAAI,CAAC,2BAA2B,EAAE,CAAC;IAAA,CACnC;IAEO,kCAAkC,CAAC,QAAgB,EAAW;QACrE,IAAI,CAAC,IAAI,CAAC,kCAAkC;YAAE,OAAO,KAAK,CAAC;QAC3D,MAAM,mBAAmB,GAAG,IAAI,CAAC,uCAAuC,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACzF,IAAI,mBAAmB,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACnD,OAAO,IAAI,CAAC,yCAAyC,CAAC,mBAAmB,CAAC,CAAC;IAAA,CAC3E;IAEO,+BAA+B,CAAC,QAAgB,EAAW;QAClE,IAAI,CAAC,IAAI,CAAC,mCAAmC;YAAE,OAAO,KAAK,CAAC;QAC5D,MAAM,mBAAmB,GAAG,IAAI,CAAC,uCAAuC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC1F,IAAI,mBAAmB,KAAK,SAAS,EAAE,CAAC;YACvC,IAAI,CAAC,8CAA8C,EAAE,CAAC;YACtD,OAAO,IAAI,CAAC;QACb,CAAC;QACD,OAAO,IAAI,CAAC,yCAAyC,CAAC,mBAAmB,CAAC,CAAC;IAAA,CAC3E;IAEO,2BAA2B,CAAC,QAAgB,EAAQ;QAC3D,IAAI,IAAI,CAAC,kCAAkC,CAAC,QAAQ,CAAC;YAAE,OAAO;QAC9D,IAAI,IAAI,CAAC,+BAA+B,CAAC,QAAQ,CAAC;YAAE,OAAO;QAC3D,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAAA,CACpC;IAED;;;;;;;OAOG;IACK,gBAAgB,GAAS;QAChC,IAAI,CAAC,WAAW,GAAG,IAAI,WAAW,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QAEpD,oDAAoD;QACpD,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,QAAQ,CAAC,CAAC,CAAC;QAEtF,kFAAkF;QAClF,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC;YACzC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBACvB,IAAI,CAAC,YAAY,CAAC,YAAY,OAAO,WAAW,CAAC,CAAC;YACnD,CAAC;QAAA,CACD,CAAC,CAAC;QAEH,mDAAmD;QACnD,IAAI,CAAC,gBAAgB,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC;YACzC,IAAI,CAAC,WAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAAA,CAChC,CAAC;IAAA,CACF;IAED;;;;;;;;;;;;;OAaG;IACK,2BAA2B,GAAS;QAC3C,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,gBAAiB,CAAC,CAAC;QACjD,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC;QACnC,IAAI,CAAC,kCAAkC,GAAG,IAAI,CAAC;QAC/C,IAAI,CAAC,mCAAmC,GAAG,KAAK,CAAC;QACjD,IAAI,CAAC,sCAAsC,EAAE,CAAC;QAC9C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACpD,IAAI,CAAC,6BAA6B,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC;YACrD,IAAI,CAAC,6BAA6B,GAAG,SAAS,CAAC;YAC/C,IAAI,CAAC,kCAAkC,GAAG,KAAK,CAAC;YAChD,IAAI,CAAC,mCAAmC,GAAG,IAAI,CAAC;YAChD,IAAI,IAAI,CAAC,iCAAiC,KAAK,MAAM,EAAE,CAAC;gBACvD,IAAI,CAAC,6CAA6C,EAAE,CAAC;YACtD,CAAC;iBAAM,CAAC;gBACP,IAAI,CAAC,8CAA8C,EAAE,CAAC;YACvD,CAAC;YACD,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAAA,CAC7B,EAAE,2CAA2C,CAAC,CAAC;IAAA,CAChD;IAEO,yCAAyC,CAChD,mBAAoE,EAC1D;QACV,IAAI,CAAC,mBAAmB;YAAE,OAAO,KAAK,CAAC;QACvC,IAAI,mBAAmB,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAChD,IAAI,mBAAmB,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC;gBACnE,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC;gBACjC,sBAAsB,CAAC,IAAI,CAAC,CAAC;gBAC7B,IAAI,CAAC,kCAAkC,GAAG,KAAK,CAAC;gBAChD,IAAI,CAAC,mCAAmC,GAAG,IAAI,CAAC;gBAChD,IAAI,CAAC,sCAAsC,EAAE,CAAC;gBAC9C,IAAI,CAAC,kCAAkC,EAAE,CAAC;YAC3C,CAAC;YACD,OAAO,IAAI,CAAC;QACb,CAAC;QAED,IAAI,CAAC,kCAAkC,GAAG,KAAK,CAAC;QAChD,IAAI,CAAC,mCAAmC,GAAG,IAAI,CAAC;QAChD,IAAI,CAAC,sCAAsC,EAAE,CAAC;QAC9C,IAAI,CAAC,kCAAkC,EAAE,CAAC;QAC1C,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IAAA,CACZ;IAEO,uCAAuC,CAC9C,QAAgB,EAChB,qBAA8B,EACgC;QAC9D,IAAI,IAAI,CAAC,iCAAiC,EAAE,CAAC;YAC5C,MAAM,gBAAgB,GAAG,IAAI,CAAC,iCAAiC,GAAG,QAAQ,CAAC;YAC3E,MAAM,mBAAmB,GAAG,wCAAwC,CAAC,gBAAgB,CAAC,CAAC;YACvF,IAAI,mBAAmB,EAAE,CAAC;gBACzB,IAAI,CAAC,sCAAsC,EAAE,CAAC;gBAC9C,OAAO,mBAAmB,CAAC;YAC5B,CAAC;YACD,IAAI,2CAA2C,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,EAAE,CAAC;gBAC1F,IAAI,CAAC,oCAAoC,CAAC,gBAAgB,CAAC,CAAC;gBAC5D,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,IAAI,CAAC,6CAA6C,EAAE,CAAC;QACtD,CAAC;QAED,MAAM,mBAAmB,GAAG,wCAAwC,CAAC,QAAQ,CAAC,CAAC;QAC/E,IAAI,mBAAmB;YAAE,OAAO,mBAAmB,CAAC;QACpD,IAAI,2CAA2C,CAAC,QAAQ,EAAE,qBAAqB,CAAC,EAAE,CAAC;YAClF,IAAI,CAAC,oCAAoC,CAAC,QAAQ,CAAC,CAAC;YACpD,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,OAAO,SAAS,CAAC;IAAA,CACjB;IAEO,oCAAoC,CAAC,QAAgB,EAAQ;QACpE,IAAI,CAAC,gDAAgD,EAAE,CAAC;QACxD,IAAI,CAAC,iCAAiC,GAAG,QAAQ,CAAC;IAAA,CAClD;IAEO,sCAAsC,GAAS;QACtD,IAAI,CAAC,gDAAgD,EAAE,CAAC;QACxD,IAAI,CAAC,iCAAiC,GAAG,EAAE,CAAC;IAAA,CAC5C;IAEO,6CAA6C,GAAS;QAC7D,IAAI,CAAC,IAAI,CAAC,iCAAiC;YAAE,OAAO;QACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,iCAAiC,CAAC;QACxD,IAAI,CAAC,sCAAsC,EAAE,CAAC;QAC9C,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAAA,CACpC;IAEO,8CAA8C,GAAS;QAC9D,IAAI,CAAC,IAAI,CAAC,iCAAiC,IAAI,IAAI,CAAC,gCAAgC;YAAE,OAAO;QAC7F,IAAI,CAAC,gCAAgC,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC;YACxD,IAAI,CAAC,gCAAgC,GAAG,SAAS,CAAC;YAClD,IAAI,CAAC,6CAA6C,EAAE,CAAC;QAAA,CACrD,EAAE,8CAA8C,CAAC,CAAC;IAAA,CACnD;IAEO,gDAAgD,GAAS;QAChE,IAAI,CAAC,IAAI,CAAC,gCAAgC;YAAE,OAAO;QACnD,YAAY,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;QACpD,IAAI,CAAC,gCAAgC,GAAG,SAAS,CAAC;IAAA,CAClD;IAEO,oBAAoB,CAAC,QAAgB,EAAQ;QACpD,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAC/B,MAAM,eAAe,GAAG,QAAQ,KAAK,IAAI,IAAI,sBAAsB,EAAE,CAAC;QACtE,MAAM,KAAK,GAAG,2BAA2B,CACxC,QAAQ,EACR,eAAe,EACf,eAAe,IAAI,uBAAuB,CAAC,OAAO,CAAC,CACnD,CAAC;QACF,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAAA,CACzB;IAEO,qBAAqB,GAAS;QACrC,IAAI,IAAI,CAAC,oBAAoB,IAAI,IAAI,CAAC,sBAAsB;YAAE,OAAO;QACrE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACnC,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC;IAAA,CACnC;IAEO,kCAAkC,GAAS;QAClD,IAAI,CAAC,IAAI,CAAC,6BAA6B;YAAE,OAAO;QAChD,YAAY,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QACjD,IAAI,CAAC,6BAA6B,GAAG,SAAS,CAAC;IAAA,CAC/C;IAED;;;;;OAKG;IACK,oBAAoB,GAAS;QACpC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;YAAE,OAAO;QACzC,IAAI,CAAC;YACJ,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;YAC1B,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,OAAO;gBAAE,OAAO;YAE/C,0EAA0E;YAC1E,0EAA0E;YAC1E,4DAA4D;YAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAC/D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,IAAI,EAAE,EAAE,yBAAyB,CAAC,CAAC;YACzG,MAAM,UAAU,GAAG;gBAClB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC;gBACtC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;gBAChC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC;aACrD,CAAC;YACF,KAAK,MAAM,UAAU,IAAI,UAAU,EAAE,CAAC;gBACrC,IAAI,CAAC;oBACJ,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAmD,CAAC;oBACxF,MAAM,CAAC,0BAA0B,EAAE,EAAE,CAAC;oBACtC,OAAO;gBACR,CAAC;gBAAC,MAAM,CAAC;oBACR,4CAA4C;gBAC7C,CAAC;YACF,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,+EAA6E;QAC9E,CAAC;IAAA,CACD;IAED,KAAK,CAAC,UAAU,CAAC,KAAK,GAAG,IAAI,EAAE,MAAM,GAAG,EAAE,EAAiB;QAC1D,MAAM,0BAA0B,GAC/B,IAAI,CAAC,sBAAsB,IAAI,IAAI,CAAC,oBAAoB,IAAI,IAAI,CAAC,kCAAkC,CAAC;QACrG,IAAI,CAAC,mCAAmC,GAAG,KAAK,CAAC;QACjD,IAAI,CAAC,sCAAsC,EAAE,CAAC;QAC9C,IAAI,CAAC,kCAAkC,EAAE,CAAC;QAC1C,IAAI,0BAA0B,EAAE,CAAC;YAChC,iEAAiE;YACjE,8CAA8C;YAC9C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAChC,IAAI,CAAC,sBAAsB,GAAG,KAAK,CAAC;YACpC,IAAI,CAAC,oBAAoB,GAAG,KAAK,CAAC;YAClC,sBAAsB,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,kCAAkC,GAAG,KAAK,CAAC;QAChD,IAAI,IAAI,CAAC,sBAAsB,EAAE,CAAC;YACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YACnC,IAAI,CAAC,sBAAsB,GAAG,KAAK,CAAC;QACrC,CAAC;QAED,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,CAAC;QAC1C,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;QAE9B,IAAI,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC;YACpB,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAAA,CAC1B,CAAC;QAEF,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QAEnC,IAAI,CAAC;YACJ,OAAO,IAAI,EAAE,CAAC;gBACb,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACvB,MAAM,QAAQ,GAAG,OAAO,GAAG,GAAG,CAAC;gBAC/B,IAAI,QAAQ,IAAI,CAAC;oBAAE,MAAM;gBACzB,IAAI,GAAG,GAAG,YAAY,IAAI,MAAM;oBAAE,MAAM;gBACxC,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;YACjF,CAAC;QACF,CAAC;gBAAS,CAAC;YACV,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAC7C,IAAI,CAAC,YAAY,GAAG,eAAe,CAAC;QACrC,CAAC;IAAA,CACD;IAED,IAAI,GAAS;QACZ,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,IAAI,CAAC,qBAAqB,EAAE,EAAE,CAAC;YAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACxD,CAAC;QAED,+BAA+B;QAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAEpC,MAAM,0BAA0B,GAC/B,IAAI,CAAC,sBAAsB,IAAI,IAAI,CAAC,oBAAoB,IAAI,IAAI,CAAC,kCAAkC,CAAC;QACrG,IAAI,CAAC,mCAAmC,GAAG,KAAK,CAAC;QACjD,IAAI,CAAC,sCAAsC,EAAE,CAAC;QAC9C,IAAI,CAAC,kCAAkC,EAAE,CAAC;QAE1C,sEAAsE;QACtE,IAAI,0BAA0B,EAAE,CAAC;YAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAChC,IAAI,CAAC,sBAAsB,GAAG,KAAK,CAAC;YACpC,IAAI,CAAC,oBAAoB,GAAG,KAAK,CAAC;YAClC,sBAAsB,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,kCAAkC,GAAG,KAAK,CAAC;QAChD,IAAI,IAAI,CAAC,sBAAsB,EAAE,CAAC;YACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YACnC,IAAI,CAAC,sBAAsB,GAAG,KAAK,CAAC;QACrC,CAAC;QAED,uBAAuB;QACvB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YAC3B,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;QAC9B,CAAC;QAED,wBAAwB;QACxB,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAC5D,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;QACnC,CAAC;QACD,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;QAC9B,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;YAC5D,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;QAChC,CAAC;QAED,sEAAsE;QACtE,yEAAyE;QACzE,sDAAsD;QACtD,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAEtB,yBAAyB;QACzB,IAAI,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;YAC9B,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvC,CAAC;IAAA,CACD;IAED,KAAK,CAAC,IAAY,EAAQ;QACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,IAAI,CAAC;gBACJ,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;YAClE,CAAC;YAAC,MAAM,CAAC;gBACR,wBAAwB;YACzB,CAAC;QACF,CAAC;IAAA,CACD;IAED,IAAI,OAAO,GAAW;QACrB,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IAAA,CACnE;IAED,IAAI,IAAI,GAAW;QAClB,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAAA,CAC9D;IAED,MAAM,CAAC,KAAa,EAAQ;QAC3B,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACf,YAAY;YACZ,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC;QACxC,CAAC;aAAM,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACtB,UAAU;YACV,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC;QACzC,CAAC;QACD,2BAA2B;IAD1B,CAED;IAED,UAAU,GAAS;QAClB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAAA,CAClC;IAED,UAAU,GAAS;QAClB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAAA,CAClC;IAED,SAAS,GAAS;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAAA,CAC/B;IAED,eAAe,GAAS;QACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAAA,CAC/B;IAED,WAAW,GAAS;QACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,sCAAsC;IAAvC,CACtC;IAED,QAAQ,CAAC,KAAa,EAAQ;QAC7B,8CAA8C;QAC9C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,8BAA8B,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAAA,CAC5E;IAED,WAAW,CAAC,MAAe,EAAQ;QAClC,IAAI,MAAM,EAAE,CAAC;YACZ,qCAAqC;YACrC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;YACxD,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBAC5B,IAAI,CAAC,gBAAgB,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;oBACzC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;gBAAA,CACxD,EAAE,8BAA8B,CAAC,CAAC;YACpC,CAAC;QACF,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAC7B,6BAA6B;YAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACxD,CAAC;IAAA,CACD;IAEO,qBAAqB,GAAY;QACxC,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAAE,OAAO,KAAK,CAAC;QACzC,aAAa,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACrC,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;QAClC,OAAO,IAAI,CAAC;IAAA,CACZ;CACD","sourcesContent":["import * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { setKittyProtocolActive } from \"./keys.ts\";\nimport { isNativeModifierPressed } from \"./native-modifiers.ts\";\nimport { StdinBuffer } from \"./stdin-buffer.ts\";\nimport { sanitizeTerminalControlPayload } from \"./terminal-control.ts\";\n\nconst cjsRequire = createRequire(import.meta.url);\n\nconst TERMINAL_PROGRESS_KEEPALIVE_MS = 1000;\nconst TERMINAL_PROGRESS_ACTIVE_SEQUENCE = \"\\x1b]9;4;3\\x07\";\nconst TERMINAL_PROGRESS_CLEAR_SEQUENCE = \"\\x1b]9;4;0\\x07\";\nconst APPLE_TERMINAL_SHIFT_ENTER_SEQUENCE = \"\\x1b[13;2u\";\nconst DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS = 7;\nconst KITTY_KEYBOARD_PROTOCOL_FALLBACK_TIMEOUT_MS = 150;\nconst KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS = 150;\nconst KITTY_KEYBOARD_PROTOCOL_QUERY = `\\x1b[>${DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS}u\\x1b[?u\\x1b[c`;\n\nexport type KeyboardProtocolNegotiationSequence =\n\t| { type: \"kitty-flags\"; flags: number }\n\t| { type: \"device-attributes\" };\n\nexport function parseKeyboardProtocolNegotiationSequence(\n\tsequence: string,\n): KeyboardProtocolNegotiationSequence | undefined {\n\tconst kittyFlags = sequence.match(/^\\x1b\\[\\?(\\d+)u$/);\n\tif (kittyFlags) {\n\t\treturn { type: \"kitty-flags\", flags: Number.parseInt(kittyFlags[1]!, 10) };\n\t}\n\tif (/^\\x1b\\[\\?[\\d;]*c$/.test(sequence)) {\n\t\treturn { type: \"device-attributes\" };\n\t}\n\treturn undefined;\n}\n\nfunction isKeyboardProtocolNegotiationSequencePrefix(sequence: string, allowBareEscapePrefix: boolean): boolean {\n\treturn (allowBareEscapePrefix && sequence === \"\\x1b\") || sequence === \"\\x1b[\" || /^\\x1b\\[\\?[\\d;]*$/.test(sequence);\n}\n\nexport function isAppleTerminalSession(): boolean {\n\treturn process.platform === \"darwin\" && process.env.TERM_PROGRAM === \"Apple_Terminal\";\n}\n\nexport function normalizeAppleTerminalInput(data: string, isAppleTerminal: boolean, isShiftPressed: boolean): string {\n\tif (isAppleTerminal && data === \"\\r\" && isShiftPressed) return APPLE_TERMINAL_SHIFT_ENTER_SEQUENCE;\n\treturn data;\n}\n\n/**\n * Minimal terminal interface for TUI\n */\nexport interface Terminal {\n\t// Start the terminal with input and resize handlers\n\tstart(onInput: (data: string) => void, onResize: () => void): void;\n\n\t// Stop the terminal and restore state\n\tstop(): void;\n\n\t/**\n\t * Drain stdin before exiting to prevent Kitty key release events from\n\t * leaking to the parent shell over slow SSH connections.\n\t * @param maxMs - Maximum time to drain (default: 1000ms)\n\t * @param idleMs - Exit early if no input arrives within this time (default: 50ms)\n\t */\n\tdrainInput(maxMs?: number, idleMs?: number): Promise<void>;\n\n\t// Write output to terminal\n\twrite(data: string): void;\n\n\t// Get terminal dimensions\n\tget columns(): number;\n\tget rows(): number;\n\n\t// Whether Kitty keyboard protocol is active\n\tget kittyProtocolActive(): boolean;\n\n\t// Cursor positioning (relative to current position)\n\tmoveBy(lines: number): void; // Move cursor up (negative) or down (positive) by N lines\n\n\t// Cursor visibility\n\thideCursor(): void; // Hide the cursor\n\tshowCursor(): void; // Show the cursor\n\n\t// Clear operations\n\tclearLine(): void; // Clear current line\n\tclearFromCursor(): void; // Clear from cursor to end of screen\n\tclearScreen(): void; // Clear entire screen and move cursor to (0,0)\n\n\t// Title operations\n\tsetTitle(title: string): void; // Set terminal window title\n\n\t// Progress indicator (OSC 9;4)\n\tsetProgress(active: boolean): void;\n}\n\n/**\n * Real terminal using process.stdin/stdout\n */\nexport class ProcessTerminal implements Terminal {\n\tprivate wasRaw = false;\n\tprivate started = false;\n\tprivate inputHandler?: (data: string) => void;\n\tprivate resizeHandler?: () => void;\n\tprivate _kittyProtocolActive = false;\n\tprivate _modifyOtherKeysActive = false;\n\tprivate keyboardProtocolPushed = false;\n\tprivate keyboardProtocolNegotiationPending = false;\n\tprivate keyboardProtocolLateResponsePending = false;\n\tprivate keyboardProtocolNegotiationBuffer = \"\";\n\tprivate keyboardProtocolFallbackTimer?: ReturnType<typeof setTimeout>;\n\tprivate keyboardProtocolBufferFlushTimer?: ReturnType<typeof setTimeout>;\n\tprivate stdinBuffer?: StdinBuffer;\n\tprivate stdinDataHandler?: (data: string) => void;\n\tprivate progressInterval?: ReturnType<typeof setInterval>;\n\tprivate writeLogPath = (() => {\n\t\tconst env = process.env.GRIP_TUI_WRITE_LOG || \"\";\n\t\tif (!env) return \"\";\n\t\ttry {\n\t\t\tif (fs.statSync(env).isDirectory()) {\n\t\t\t\tconst now = new Date();\n\t\t\t\tconst ts = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, \"0\")}-${String(now.getDate()).padStart(2, \"0\")}_${String(now.getHours()).padStart(2, \"0\")}-${String(now.getMinutes()).padStart(2, \"0\")}-${String(now.getSeconds()).padStart(2, \"0\")}`;\n\t\t\t\treturn path.join(env, `tui-${ts}-${process.pid}.log`);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Not an existing directory - use as-is (file path)\n\t\t}\n\t\treturn env;\n\t})();\n\n\tget kittyProtocolActive(): boolean {\n\t\treturn this._kittyProtocolActive;\n\t}\n\n\tstart(onInput: (data: string) => void, onResize: () => void): void {\n\t\tif (this.started) {\n\t\t\tthis.inputHandler = onInput;\n\t\t\tif (this.resizeHandler !== onResize) {\n\t\t\t\tif (this.resizeHandler) process.stdout.removeListener(\"resize\", this.resizeHandler);\n\t\t\t\tthis.resizeHandler = onResize;\n\t\t\t\tprocess.stdout.on(\"resize\", onResize);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis.started = true;\n\t\tthis.inputHandler = onInput;\n\t\tthis.resizeHandler = onResize;\n\t\t// Save previous state and enable raw mode\n\t\tthis.wasRaw = process.stdin.isRaw || false;\n\t\tif (process.stdin.setRawMode) {\n\t\t\tprocess.stdin.setRawMode(true);\n\t\t}\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\t\tprocess.stdin.resume();\n\n\t\t// Enable bracketed paste mode - terminal will wrap pastes in \\x1b[200~ ... \\x1b[201~\n\t\tprocess.stdout.write(\"\\x1b[?2004h\");\n\n\t\t// Set up resize handler immediately\n\t\tprocess.stdout.on(\"resize\", this.resizeHandler);\n\n\t\t// Refresh terminal dimensions - they may be stale after suspend/resume\n\t\t// (SIGWINCH is lost while process is stopped). Unix only.\n\t\tif (process.platform !== \"win32\") {\n\t\t\tprocess.kill(process.pid, \"SIGWINCH\");\n\t\t}\n\n\t\t// On Windows, enable ENABLE_VIRTUAL_TERMINAL_INPUT so the console sends\n\t\t// VT escape sequences (e.g. \\x1b[Z for Shift+Tab) instead of raw console\n\t\t// events that lose modifier information. Must run AFTER setRawMode(true)\n\t\t// since that resets console mode flags.\n\t\tthis.enableWindowsVTInput();\n\n\t\t// Query and enable Kitty keyboard protocol\n\t\t// The query handler intercepts input temporarily, then installs the user's handler\n\t\t// See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/\n\t\tthis.queryAndEnableKittyProtocol();\n\t}\n\n\tprivate handleInitialKeyboardProtocolInput(sequence: string): boolean {\n\t\tif (!this.keyboardProtocolNegotiationPending) return false;\n\t\tconst negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence, true);\n\t\tif (negotiationSequence === \"pending\") return true;\n\t\treturn this.handleKeyboardProtocolNegotiationSequence(negotiationSequence);\n\t}\n\n\tprivate handleLateKeyboardProtocolInput(sequence: string): boolean {\n\t\tif (!this.keyboardProtocolLateResponsePending) return false;\n\t\tconst negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence, false);\n\t\tif (negotiationSequence === \"pending\") {\n\t\t\tthis.scheduleKeyboardProtocolNegotiationBufferFlush();\n\t\t\treturn true;\n\t\t}\n\t\treturn this.handleKeyboardProtocolNegotiationSequence(negotiationSequence);\n\t}\n\n\tprivate handleBufferedInputSequence(sequence: string): void {\n\t\tif (this.handleInitialKeyboardProtocolInput(sequence)) return;\n\t\tif (this.handleLateKeyboardProtocolInput(sequence)) return;\n\t\tthis.forwardInputSequence(sequence);\n\t}\n\n\t/**\n\t * Set up StdinBuffer to split batched input into individual sequences.\n\t * This ensures components receive single events, making matchesKey/isKeyRelease work correctly.\n\t *\n\t * Also watches for Kitty protocol response and enables it when detected.\n\t * This is done here (after stdinBuffer parsing) rather than on raw stdin\n\t * to handle the case where the response arrives split across multiple events.\n\t */\n\tprivate setupStdinBuffer(): void {\n\t\tthis.stdinBuffer = new StdinBuffer({ timeout: 10 });\n\n\t\t// Forward individual sequences to the input handler\n\t\tthis.stdinBuffer.on(\"data\", (sequence) => this.handleBufferedInputSequence(sequence));\n\n\t\t// Re-wrap paste content with bracketed paste markers for existing editor handling\n\t\tthis.stdinBuffer.on(\"paste\", (content) => {\n\t\t\tif (this.inputHandler) {\n\t\t\t\tthis.inputHandler(`\\x1b[200~${content}\\x1b[201~`);\n\t\t\t}\n\t\t});\n\n\t\t// Handler that pipes stdin data through the buffer\n\t\tthis.stdinDataHandler = (data: string) => {\n\t\t\tthis.stdinBuffer!.process(data);\n\t\t};\n\t}\n\n\t/**\n\t * Query terminal for Kitty keyboard protocol support and enable it if available.\n\t *\n\t * Kitty's progressive enhancement detection requires requesting the desired\n\t * flags before querying them. The trailing DA query is a sentinel supported by\n\t * terminals that do not know Kitty keyboard protocol. A short timeout remains\n\t * as a backup for terminals, PTYs, and SSH sessions that delay, split, or drop\n\t * the DA response.\n\t *\n\t * The requested flags are:\n\t * - 1 = disambiguate escape codes\n\t * - 2 = report event types (press/repeat/release)\n\t * - 4 = report alternate keys (shifted key, base layout key)\n\t */\n\tprivate queryAndEnableKittyProtocol(): void {\n\t\tthis.setupStdinBuffer();\n\t\tprocess.stdin.on(\"data\", this.stdinDataHandler!);\n\t\tthis.keyboardProtocolPushed = true;\n\t\tthis.keyboardProtocolNegotiationPending = true;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tprocess.stdout.write(KITTY_KEYBOARD_PROTOCOL_QUERY);\n\t\tthis.keyboardProtocolFallbackTimer = setTimeout(() => {\n\t\t\tthis.keyboardProtocolFallbackTimer = undefined;\n\t\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\t\tif (this.keyboardProtocolNegotiationBuffer === \"\\x1b\") {\n\t\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t\t} else {\n\t\t\t\tthis.scheduleKeyboardProtocolNegotiationBufferFlush();\n\t\t\t}\n\t\t\tthis.enableModifyOtherKeys();\n\t\t}, KITTY_KEYBOARD_PROTOCOL_FALLBACK_TIMEOUT_MS);\n\t}\n\n\tprivate handleKeyboardProtocolNegotiationSequence(\n\t\tnegotiationSequence: KeyboardProtocolNegotiationSequence | undefined,\n\t): boolean {\n\t\tif (!negotiationSequence) return false;\n\t\tif (negotiationSequence.type === \"kitty-flags\") {\n\t\t\tif (negotiationSequence.flags !== 0 && !this._kittyProtocolActive) {\n\t\t\t\tthis._kittyProtocolActive = true;\n\t\t\t\tsetKittyProtocolActive(true);\n\t\t\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\t\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\t\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\t\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\tthis.enableModifyOtherKeys();\n\t\treturn true;\n\t}\n\n\tprivate readKeyboardProtocolNegotiationSequence(\n\t\tsequence: string,\n\t\tallowBareEscapePrefix: boolean,\n\t): KeyboardProtocolNegotiationSequence | \"pending\" | undefined {\n\t\tif (this.keyboardProtocolNegotiationBuffer) {\n\t\t\tconst bufferedSequence = this.keyboardProtocolNegotiationBuffer + sequence;\n\t\t\tconst negotiationSequence = parseKeyboardProtocolNegotiationSequence(bufferedSequence);\n\t\t\tif (negotiationSequence) {\n\t\t\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\t\t\treturn negotiationSequence;\n\t\t\t}\n\t\t\tif (isKeyboardProtocolNegotiationSequencePrefix(bufferedSequence, allowBareEscapePrefix)) {\n\t\t\t\tthis.setKeyboardProtocolNegotiationBuffer(bufferedSequence);\n\t\t\t\treturn \"pending\";\n\t\t\t}\n\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t}\n\n\t\tconst negotiationSequence = parseKeyboardProtocolNegotiationSequence(sequence);\n\t\tif (negotiationSequence) return negotiationSequence;\n\t\tif (isKeyboardProtocolNegotiationSequencePrefix(sequence, allowBareEscapePrefix)) {\n\t\t\tthis.setKeyboardProtocolNegotiationBuffer(sequence);\n\t\t\treturn \"pending\";\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate setKeyboardProtocolNegotiationBuffer(sequence: string): void {\n\t\tthis.clearKeyboardProtocolNegotiationBufferFlushTimer();\n\t\tthis.keyboardProtocolNegotiationBuffer = sequence;\n\t}\n\n\tprivate clearKeyboardProtocolNegotiationBuffer(): void {\n\t\tthis.clearKeyboardProtocolNegotiationBufferFlushTimer();\n\t\tthis.keyboardProtocolNegotiationBuffer = \"\";\n\t}\n\n\tprivate flushKeyboardProtocolNegotiationBufferAsInput(): void {\n\t\tif (!this.keyboardProtocolNegotiationBuffer) return;\n\t\tconst sequence = this.keyboardProtocolNegotiationBuffer;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.forwardInputSequence(sequence);\n\t}\n\n\tprivate scheduleKeyboardProtocolNegotiationBufferFlush(): void {\n\t\tif (!this.keyboardProtocolNegotiationBuffer || this.keyboardProtocolBufferFlushTimer) return;\n\t\tthis.keyboardProtocolBufferFlushTimer = setTimeout(() => {\n\t\t\tthis.keyboardProtocolBufferFlushTimer = undefined;\n\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t}, KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS);\n\t}\n\n\tprivate clearKeyboardProtocolNegotiationBufferFlushTimer(): void {\n\t\tif (!this.keyboardProtocolBufferFlushTimer) return;\n\t\tclearTimeout(this.keyboardProtocolBufferFlushTimer);\n\t\tthis.keyboardProtocolBufferFlushTimer = undefined;\n\t}\n\n\tprivate forwardInputSequence(sequence: string): void {\n\t\tif (!this.inputHandler) return;\n\t\tconst isAppleTerminal = sequence === \"\\r\" && isAppleTerminalSession();\n\t\tconst input = normalizeAppleTerminalInput(\n\t\t\tsequence,\n\t\t\tisAppleTerminal,\n\t\t\tisAppleTerminal && isNativeModifierPressed(\"shift\"),\n\t\t);\n\t\tthis.inputHandler(input);\n\t}\n\n\tprivate enableModifyOtherKeys(): void {\n\t\tif (this._kittyProtocolActive || this._modifyOtherKeysActive) return;\n\t\tprocess.stdout.write(\"\\x1b[>4;2m\");\n\t\tthis._modifyOtherKeysActive = true;\n\t}\n\n\tprivate clearKeyboardProtocolFallbackTimer(): void {\n\t\tif (!this.keyboardProtocolFallbackTimer) return;\n\t\tclearTimeout(this.keyboardProtocolFallbackTimer);\n\t\tthis.keyboardProtocolFallbackTimer = undefined;\n\t}\n\n\t/**\n\t * On Windows, add ENABLE_VIRTUAL_TERMINAL_INPUT (0x0200) to the stdin\n\t * console handle so the terminal sends VT sequences for modified keys\n\t * (e.g. \\x1b[Z for Shift+Tab). Without this, libuv's ReadConsoleInputW\n\t * discards modifier state and Shift+Tab arrives as plain \\t.\n\t */\n\tprivate enableWindowsVTInput(): void {\n\t\tif (process.platform !== \"win32\") return;\n\t\ttry {\n\t\t\tconst arch = process.arch;\n\t\t\tif (arch !== \"x64\" && arch !== \"arm64\") return;\n\n\t\t\t// Dynamic require so non-Windows and bundled/browser paths never load the\n\t\t\t// native helper. In the npm package native/ is next to dist/; in compiled\n\t\t\t// binary archives native/ is copied next to the executable.\n\t\t\tconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\t\t\tconst nativePath = path.join(\"native\", \"win32\", \"prebuilds\", `win32-${arch}`, \"win32-console-mode.node\");\n\t\t\tconst candidates = [\n\t\t\t\tpath.join(moduleDir, \"..\", nativePath),\n\t\t\t\tpath.join(moduleDir, nativePath),\n\t\t\t\tpath.join(path.dirname(process.execPath), nativePath),\n\t\t\t];\n\t\t\tfor (const modulePath of candidates) {\n\t\t\t\ttry {\n\t\t\t\t\tconst helper = cjsRequire(modulePath) as { enableVirtualTerminalInput?: () => boolean };\n\t\t\t\t\thelper.enableVirtualTerminalInput?.();\n\t\t\t\t\treturn;\n\t\t\t\t} catch {\n\t\t\t\t\t// Try the next possible packaging location.\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Native helper not available — Shift+Tab won't be distinguishable from Tab.\n\t\t}\n\t}\n\n\tasync drainInput(maxMs = 1000, idleMs = 50): Promise<void> {\n\t\tconst shouldDisableKittyProtocol =\n\t\t\tthis.keyboardProtocolPushed || this._kittyProtocolActive || this.keyboardProtocolNegotiationPending;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\tif (shouldDisableKittyProtocol) {\n\t\t\t// Disable Kitty keyboard protocol first so any late key releases\n\t\t\t// do not generate new Kitty escape sequences.\n\t\t\tprocess.stdout.write(\"\\x1b[<u\");\n\t\t\tthis.keyboardProtocolPushed = false;\n\t\t\tthis._kittyProtocolActive = false;\n\t\t\tsetKittyProtocolActive(false);\n\t\t}\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tif (this._modifyOtherKeysActive) {\n\t\t\tprocess.stdout.write(\"\\x1b[>4;0m\");\n\t\t\tthis._modifyOtherKeysActive = false;\n\t\t}\n\n\t\tconst previousHandler = this.inputHandler;\n\t\tthis.inputHandler = undefined;\n\n\t\tlet lastDataTime = Date.now();\n\t\tconst onData = () => {\n\t\t\tlastDataTime = Date.now();\n\t\t};\n\n\t\tprocess.stdin.on(\"data\", onData);\n\t\tconst endTime = Date.now() + maxMs;\n\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst now = Date.now();\n\t\t\t\tconst timeLeft = endTime - now;\n\t\t\t\tif (timeLeft <= 0) break;\n\t\t\t\tif (now - lastDataTime >= idleMs) break;\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, Math.min(idleMs, timeLeft)));\n\t\t\t}\n\t\t} finally {\n\t\t\tprocess.stdin.removeListener(\"data\", onData);\n\t\t\tthis.inputHandler = previousHandler;\n\t\t}\n\t}\n\n\tstop(): void {\n\t\tthis.started = false;\n\t\tif (this.clearProgressInterval()) {\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE);\n\t\t}\n\n\t\t// Disable bracketed paste mode\n\t\tprocess.stdout.write(\"\\x1b[?2004l\");\n\n\t\tconst shouldDisableKittyProtocol =\n\t\t\tthis.keyboardProtocolPushed || this._kittyProtocolActive || this.keyboardProtocolNegotiationPending;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\n\t\t// Disable Kitty keyboard protocol if not already done by drainInput()\n\t\tif (shouldDisableKittyProtocol) {\n\t\t\tprocess.stdout.write(\"\\x1b[<u\");\n\t\t\tthis.keyboardProtocolPushed = false;\n\t\t\tthis._kittyProtocolActive = false;\n\t\t\tsetKittyProtocolActive(false);\n\t\t}\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tif (this._modifyOtherKeysActive) {\n\t\t\tprocess.stdout.write(\"\\x1b[>4;0m\");\n\t\t\tthis._modifyOtherKeysActive = false;\n\t\t}\n\n\t\t// Clean up StdinBuffer\n\t\tif (this.stdinBuffer) {\n\t\t\tthis.stdinBuffer.destroy();\n\t\t\tthis.stdinBuffer = undefined;\n\t\t}\n\n\t\t// Remove event handlers\n\t\tif (this.stdinDataHandler) {\n\t\t\tprocess.stdin.removeListener(\"data\", this.stdinDataHandler);\n\t\t\tthis.stdinDataHandler = undefined;\n\t\t}\n\t\tthis.inputHandler = undefined;\n\t\tif (this.resizeHandler) {\n\t\t\tprocess.stdout.removeListener(\"resize\", this.resizeHandler);\n\t\t\tthis.resizeHandler = undefined;\n\t\t}\n\n\t\t// Pause stdin to prevent any buffered input (e.g., Ctrl+D) from being\n\t\t// re-interpreted after raw mode is disabled. This fixes a race condition\n\t\t// where Ctrl+D could close the parent shell over SSH.\n\t\tprocess.stdin.pause();\n\n\t\t// Restore raw mode state\n\t\tif (process.stdin.setRawMode) {\n\t\t\tprocess.stdin.setRawMode(this.wasRaw);\n\t\t}\n\t}\n\n\twrite(data: string): void {\n\t\tprocess.stdout.write(data);\n\t\tif (this.writeLogPath) {\n\t\t\ttry {\n\t\t\t\tfs.appendFileSync(this.writeLogPath, data, { encoding: \"utf8\" });\n\t\t\t} catch {\n\t\t\t\t// Ignore logging errors\n\t\t\t}\n\t\t}\n\t}\n\n\tget columns(): number {\n\t\treturn process.stdout.columns || Number(process.env.COLUMNS) || 80;\n\t}\n\n\tget rows(): number {\n\t\treturn process.stdout.rows || Number(process.env.LINES) || 24;\n\t}\n\n\tmoveBy(lines: number): void {\n\t\tif (lines > 0) {\n\t\t\t// Move down\n\t\t\tprocess.stdout.write(`\\x1b[${lines}B`);\n\t\t} else if (lines < 0) {\n\t\t\t// Move up\n\t\t\tprocess.stdout.write(`\\x1b[${-lines}A`);\n\t\t}\n\t\t// lines === 0: no movement\n\t}\n\n\thideCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[?25l\");\n\t}\n\n\tshowCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[?25h\");\n\t}\n\n\tclearLine(): void {\n\t\tprocess.stdout.write(\"\\x1b[K\");\n\t}\n\n\tclearFromCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[J\");\n\t}\n\n\tclearScreen(): void {\n\t\tprocess.stdout.write(\"\\x1b[2J\\x1b[H\"); // Clear screen and move to home (1,1)\n\t}\n\n\tsetTitle(title: string): void {\n\t\t// OSC 0;title BEL - set terminal window title\n\t\tprocess.stdout.write(`\\x1b]0;${sanitizeTerminalControlPayload(title)}\\x07`);\n\t}\n\n\tsetProgress(active: boolean): void {\n\t\tif (active) {\n\t\t\t// OSC 9;4;3 - indeterminate progress\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE);\n\t\t\tif (!this.progressInterval) {\n\t\t\t\tthis.progressInterval = setInterval(() => {\n\t\t\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE);\n\t\t\t\t}, TERMINAL_PROGRESS_KEEPALIVE_MS);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.clearProgressInterval();\n\t\t\t// OSC 9;4;0 - clear progress\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE);\n\t\t}\n\t}\n\n\tprivate clearProgressInterval(): boolean {\n\t\tif (!this.progressInterval) return false;\n\t\tclearInterval(this.progressInterval);\n\t\tthis.progressInterval = undefined;\n\t\treturn true;\n\t}\n}\n"]}
1
+ {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../src/terminal.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { setKittyProtocolActive } from \"./keys.ts\";\nimport { isNativeModifierPressed } from \"./native-modifiers.ts\";\nimport { StdinBuffer } from \"./stdin-buffer.ts\";\nimport { sanitizeTerminalControlPayload } from \"./terminal-control.ts\";\n\nconst cjsRequire = createRequire(import.meta.url);\n\nconst TERMINAL_PROGRESS_KEEPALIVE_MS = 1000;\nconst TERMINAL_PROGRESS_ACTIVE_SEQUENCE = \"\\x1b]9;4;3\\x07\";\nconst TERMINAL_PROGRESS_CLEAR_SEQUENCE = \"\\x1b]9;4;0\\x07\";\nconst APPLE_TERMINAL_SHIFT_ENTER_SEQUENCE = \"\\x1b[13;2u\";\nconst DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS = 7;\nconst KITTY_KEYBOARD_PROTOCOL_FALLBACK_TIMEOUT_MS = 150;\nconst KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS = 150;\nconst KITTY_KEYBOARD_PROTOCOL_QUERY = `\\x1b[>${DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS}u\\x1b[?u\\x1b[c`;\n\nexport type KeyboardProtocolNegotiationSequence =\n\t| { type: \"kitty-flags\"; flags: number }\n\t| { type: \"device-attributes\" };\n\nexport function parseKeyboardProtocolNegotiationSequence(\n\tsequence: string,\n): KeyboardProtocolNegotiationSequence | undefined {\n\tconst kittyFlags = sequence.match(/^\\x1b\\[\\?(\\d+)u$/);\n\tif (kittyFlags) {\n\t\treturn { type: \"kitty-flags\", flags: Number.parseInt(kittyFlags[1]!, 10) };\n\t}\n\tif (/^\\x1b\\[\\?[\\d;]*c$/.test(sequence)) {\n\t\treturn { type: \"device-attributes\" };\n\t}\n\treturn undefined;\n}\n\nfunction isKeyboardProtocolNegotiationSequencePrefix(sequence: string, allowBareEscapePrefix: boolean): boolean {\n\treturn (allowBareEscapePrefix && sequence === \"\\x1b\") || sequence === \"\\x1b[\" || /^\\x1b\\[\\?[\\d;]*$/.test(sequence);\n}\n\nexport function isAppleTerminalSession(): boolean {\n\treturn process.platform === \"darwin\" && process.env.TERM_PROGRAM === \"Apple_Terminal\";\n}\n\nexport function normalizeAppleTerminalInput(data: string, isAppleTerminal: boolean, isShiftPressed: boolean): string {\n\tif (isAppleTerminal && data === \"\\r\" && isShiftPressed) return APPLE_TERMINAL_SHIFT_ENTER_SEQUENCE;\n\treturn data;\n}\n\n/**\n * Minimal terminal interface for TUI\n */\nexport interface Terminal {\n\t// Start the terminal with input and resize handlers\n\tstart(onInput: (data: string) => void, onResize: () => void): void;\n\n\t// Stop the terminal and restore state\n\tstop(): void;\n\n\t/**\n\t * Drain stdin before exiting to prevent Kitty key release events from\n\t * leaking to the parent shell over slow SSH connections.\n\t * @param maxMs - Maximum time to drain (default: 1000ms)\n\t * @param idleMs - Exit early if no input arrives within this time (default: 50ms)\n\t */\n\tdrainInput(maxMs?: number, idleMs?: number): Promise<void>;\n\n\t// Write output to terminal\n\twrite(data: string): void;\n\n\t// Get terminal dimensions\n\tget columns(): number;\n\tget rows(): number;\n\n\t// Whether Kitty keyboard protocol is active\n\tget kittyProtocolActive(): boolean;\n\n\t// Cursor positioning (relative to current position)\n\tmoveBy(lines: number): void; // Move cursor up (negative) or down (positive) by N lines\n\n\t// Cursor visibility\n\thideCursor(): void; // Hide the cursor\n\tshowCursor(): void; // Show the cursor\n\n\t// Clear operations\n\tclearLine(): void; // Clear current line\n\tclearFromCursor(): void; // Clear from cursor to end of screen\n\tclearScreen(): void; // Clear entire screen and move cursor to (0,0)\n\n\t// Title operations\n\tsetTitle(title: string): void; // Set terminal window title\n\n\t// Progress indicator (OSC 9;4)\n\tsetProgress(active: boolean): void;\n}\n\n/**\n * Real terminal using process.stdin/stdout\n */\nexport class ProcessTerminal implements Terminal {\n\tprivate wasRaw = false;\n\tprivate started = false;\n\tprivate inputHandler?: (data: string) => void;\n\tprivate resizeHandler?: () => void;\n\tprivate _kittyProtocolActive = false;\n\tprivate _modifyOtherKeysActive = false;\n\tprivate keyboardProtocolPushed = false;\n\tprivate keyboardProtocolNegotiationPending = false;\n\tprivate keyboardProtocolLateResponsePending = false;\n\tprivate keyboardProtocolNegotiationBuffer = \"\";\n\tprivate keyboardProtocolFallbackTimer?: ReturnType<typeof setTimeout>;\n\tprivate keyboardProtocolBufferFlushTimer?: ReturnType<typeof setTimeout>;\n\tprivate stdinBuffer?: StdinBuffer;\n\tprivate stdinDataHandler?: (data: string) => void;\n\tprivate progressInterval?: ReturnType<typeof setInterval>;\n\tprivate writeLogPath = (() => {\n\t\tconst env = process.env.GRIP_TUI_WRITE_LOG || \"\";\n\t\tif (!env) return \"\";\n\t\ttry {\n\t\t\tif (fs.statSync(env).isDirectory()) {\n\t\t\t\tconst now = new Date();\n\t\t\t\tconst ts = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, \"0\")}-${String(now.getDate()).padStart(2, \"0\")}_${String(now.getHours()).padStart(2, \"0\")}-${String(now.getMinutes()).padStart(2, \"0\")}-${String(now.getSeconds()).padStart(2, \"0\")}`;\n\t\t\t\treturn path.join(env, `tui-${ts}-${process.pid}.log`);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Not an existing directory - use as-is (file path)\n\t\t}\n\t\treturn env;\n\t})();\n\n\tget kittyProtocolActive(): boolean {\n\t\treturn this._kittyProtocolActive;\n\t}\n\n\tstart(onInput: (data: string) => void, onResize: () => void): void {\n\t\tif (this.started) {\n\t\t\tthis.inputHandler = onInput;\n\t\t\tif (this.resizeHandler !== onResize) {\n\t\t\t\tif (this.resizeHandler) process.stdout.removeListener(\"resize\", this.resizeHandler);\n\t\t\t\tthis.resizeHandler = onResize;\n\t\t\t\tprocess.stdout.on(\"resize\", onResize);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis.started = true;\n\t\tthis.inputHandler = onInput;\n\t\tthis.resizeHandler = onResize;\n\t\t// Save previous state and enable raw mode\n\t\tthis.wasRaw = process.stdin.isRaw || false;\n\t\tif (process.stdin.setRawMode) {\n\t\t\tprocess.stdin.setRawMode(true);\n\t\t}\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\t\tprocess.stdin.resume();\n\n\t\t// Enable bracketed paste mode - terminal will wrap pastes in \\x1b[200~ ... \\x1b[201~\n\t\tprocess.stdout.write(\"\\x1b[?2004h\");\n\n\t\t// Set up resize handler immediately\n\t\tprocess.stdout.on(\"resize\", this.resizeHandler);\n\n\t\t// Refresh terminal dimensions - they may be stale after suspend/resume\n\t\t// (SIGWINCH is lost while process is stopped). Unix only.\n\t\tif (process.platform !== \"win32\") {\n\t\t\tprocess.kill(process.pid, \"SIGWINCH\");\n\t\t}\n\n\t\t// On Windows, enable ENABLE_VIRTUAL_TERMINAL_INPUT so the console sends\n\t\t// VT escape sequences (e.g. \\x1b[Z for Shift+Tab) instead of raw console\n\t\t// events that lose modifier information. Must run AFTER setRawMode(true)\n\t\t// since that resets console mode flags.\n\t\tthis.enableWindowsVTInput();\n\n\t\t// Query and enable Kitty keyboard protocol\n\t\t// The query handler intercepts input temporarily, then installs the user's handler\n\t\t// See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/\n\t\tthis.queryAndEnableKittyProtocol();\n\t}\n\n\tprivate handleInitialKeyboardProtocolInput(sequence: string): boolean {\n\t\tif (!this.keyboardProtocolNegotiationPending) return false;\n\t\tconst negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence, true);\n\t\tif (negotiationSequence === \"pending\") return true;\n\t\treturn this.handleKeyboardProtocolNegotiationSequence(negotiationSequence);\n\t}\n\n\tprivate handleLateKeyboardProtocolInput(sequence: string): boolean {\n\t\tif (!this.keyboardProtocolLateResponsePending) return false;\n\t\tconst negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence, false);\n\t\tif (negotiationSequence === \"pending\") {\n\t\t\tthis.scheduleKeyboardProtocolNegotiationBufferFlush();\n\t\t\treturn true;\n\t\t}\n\t\treturn this.handleKeyboardProtocolNegotiationSequence(negotiationSequence);\n\t}\n\n\tprivate handleBufferedInputSequence(sequence: string): void {\n\t\tif (this.handleInitialKeyboardProtocolInput(sequence)) return;\n\t\tif (this.handleLateKeyboardProtocolInput(sequence)) return;\n\t\tthis.forwardInputSequence(sequence);\n\t}\n\n\t/**\n\t * Set up StdinBuffer to split batched input into individual sequences.\n\t * This ensures components receive single events, making matchesKey/isKeyRelease work correctly.\n\t *\n\t * Also watches for Kitty protocol response and enables it when detected.\n\t * This is done here (after stdinBuffer parsing) rather than on raw stdin\n\t * to handle the case where the response arrives split across multiple events.\n\t */\n\tprivate setupStdinBuffer(): void {\n\t\tthis.stdinBuffer = new StdinBuffer({ timeout: 10 });\n\n\t\t// Forward individual sequences to the input handler\n\t\tthis.stdinBuffer.on(\"data\", (sequence) => this.handleBufferedInputSequence(sequence));\n\n\t\t// Re-wrap paste content with bracketed paste markers for existing editor handling\n\t\tthis.stdinBuffer.on(\"paste\", (content) => {\n\t\t\tif (this.inputHandler) {\n\t\t\t\tthis.inputHandler(`\\x1b[200~${content}\\x1b[201~`);\n\t\t\t}\n\t\t});\n\n\t\t// Handler that pipes stdin data through the buffer\n\t\tthis.stdinDataHandler = (data: string) => {\n\t\t\tthis.stdinBuffer!.process(data);\n\t\t};\n\t}\n\n\t/**\n\t * Query terminal for Kitty keyboard protocol support and enable it if available.\n\t *\n\t * Kitty's progressive enhancement detection requires requesting the desired\n\t * flags before querying them. The trailing DA query is a sentinel supported by\n\t * terminals that do not know Kitty keyboard protocol. A short timeout remains\n\t * as a backup for terminals, PTYs, and SSH sessions that delay, split, or drop\n\t * the DA response.\n\t *\n\t * The requested flags are:\n\t * - 1 = disambiguate escape codes\n\t * - 2 = report event types (press/repeat/release)\n\t * - 4 = report alternate keys (shifted key, base layout key)\n\t */\n\tprivate queryAndEnableKittyProtocol(): void {\n\t\tthis.setupStdinBuffer();\n\t\tprocess.stdin.on(\"data\", this.stdinDataHandler!);\n\t\tthis.keyboardProtocolPushed = true;\n\t\tthis.keyboardProtocolNegotiationPending = true;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tprocess.stdout.write(KITTY_KEYBOARD_PROTOCOL_QUERY);\n\t\tthis.keyboardProtocolFallbackTimer = setTimeout(() => {\n\t\t\tthis.keyboardProtocolFallbackTimer = undefined;\n\t\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\t\tif (this.keyboardProtocolNegotiationBuffer === \"\\x1b\") {\n\t\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t\t} else {\n\t\t\t\tthis.scheduleKeyboardProtocolNegotiationBufferFlush();\n\t\t\t}\n\t\t\tthis.enableModifyOtherKeys();\n\t\t}, KITTY_KEYBOARD_PROTOCOL_FALLBACK_TIMEOUT_MS);\n\t}\n\n\tprivate handleKeyboardProtocolNegotiationSequence(\n\t\tnegotiationSequence: KeyboardProtocolNegotiationSequence | undefined,\n\t): boolean {\n\t\tif (!negotiationSequence) return false;\n\t\tif (negotiationSequence.type === \"kitty-flags\") {\n\t\t\tif (negotiationSequence.flags !== 0 && !this._kittyProtocolActive) {\n\t\t\t\tthis._kittyProtocolActive = true;\n\t\t\t\tsetKittyProtocolActive(true);\n\t\t\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\t\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\t\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\t\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\tthis.enableModifyOtherKeys();\n\t\treturn true;\n\t}\n\n\tprivate readKeyboardProtocolNegotiationSequence(\n\t\tsequence: string,\n\t\tallowBareEscapePrefix: boolean,\n\t): KeyboardProtocolNegotiationSequence | \"pending\" | undefined {\n\t\tif (this.keyboardProtocolNegotiationBuffer) {\n\t\t\tconst bufferedSequence = this.keyboardProtocolNegotiationBuffer + sequence;\n\t\t\tconst negotiationSequence = parseKeyboardProtocolNegotiationSequence(bufferedSequence);\n\t\t\tif (negotiationSequence) {\n\t\t\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\t\t\treturn negotiationSequence;\n\t\t\t}\n\t\t\tif (isKeyboardProtocolNegotiationSequencePrefix(bufferedSequence, allowBareEscapePrefix)) {\n\t\t\t\tthis.setKeyboardProtocolNegotiationBuffer(bufferedSequence);\n\t\t\t\treturn \"pending\";\n\t\t\t}\n\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t}\n\n\t\tconst negotiationSequence = parseKeyboardProtocolNegotiationSequence(sequence);\n\t\tif (negotiationSequence) return negotiationSequence;\n\t\tif (isKeyboardProtocolNegotiationSequencePrefix(sequence, allowBareEscapePrefix)) {\n\t\t\tthis.setKeyboardProtocolNegotiationBuffer(sequence);\n\t\t\treturn \"pending\";\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate setKeyboardProtocolNegotiationBuffer(sequence: string): void {\n\t\tthis.clearKeyboardProtocolNegotiationBufferFlushTimer();\n\t\tthis.keyboardProtocolNegotiationBuffer = sequence;\n\t}\n\n\tprivate clearKeyboardProtocolNegotiationBuffer(): void {\n\t\tthis.clearKeyboardProtocolNegotiationBufferFlushTimer();\n\t\tthis.keyboardProtocolNegotiationBuffer = \"\";\n\t}\n\n\tprivate flushKeyboardProtocolNegotiationBufferAsInput(): void {\n\t\tif (!this.keyboardProtocolNegotiationBuffer) return;\n\t\tconst sequence = this.keyboardProtocolNegotiationBuffer;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.forwardInputSequence(sequence);\n\t}\n\n\tprivate scheduleKeyboardProtocolNegotiationBufferFlush(): void {\n\t\tif (!this.keyboardProtocolNegotiationBuffer || this.keyboardProtocolBufferFlushTimer) return;\n\t\tthis.keyboardProtocolBufferFlushTimer = setTimeout(() => {\n\t\t\tthis.keyboardProtocolBufferFlushTimer = undefined;\n\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t}, KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS);\n\t}\n\n\tprivate clearKeyboardProtocolNegotiationBufferFlushTimer(): void {\n\t\tif (!this.keyboardProtocolBufferFlushTimer) return;\n\t\tclearTimeout(this.keyboardProtocolBufferFlushTimer);\n\t\tthis.keyboardProtocolBufferFlushTimer = undefined;\n\t}\n\n\tprivate forwardInputSequence(sequence: string): void {\n\t\tif (!this.inputHandler) return;\n\t\tconst isAppleTerminal = sequence === \"\\r\" && isAppleTerminalSession();\n\t\tconst input = normalizeAppleTerminalInput(\n\t\t\tsequence,\n\t\t\tisAppleTerminal,\n\t\t\tisAppleTerminal && isNativeModifierPressed(\"shift\"),\n\t\t);\n\t\tthis.inputHandler(input);\n\t}\n\n\tprivate enableModifyOtherKeys(): void {\n\t\tif (this._kittyProtocolActive || this._modifyOtherKeysActive) return;\n\t\tprocess.stdout.write(\"\\x1b[>4;2m\");\n\t\tthis._modifyOtherKeysActive = true;\n\t}\n\n\tprivate clearKeyboardProtocolFallbackTimer(): void {\n\t\tif (!this.keyboardProtocolFallbackTimer) return;\n\t\tclearTimeout(this.keyboardProtocolFallbackTimer);\n\t\tthis.keyboardProtocolFallbackTimer = undefined;\n\t}\n\n\t/**\n\t * On Windows, add ENABLE_VIRTUAL_TERMINAL_INPUT (0x0200) to the stdin\n\t * console handle so the terminal sends VT sequences for modified keys\n\t * (e.g. \\x1b[Z for Shift+Tab). Without this, libuv's ReadConsoleInputW\n\t * discards modifier state and Shift+Tab arrives as plain \\t.\n\t */\n\tprivate enableWindowsVTInput(): void {\n\t\tif (process.platform !== \"win32\") return;\n\t\ttry {\n\t\t\tconst arch = process.arch;\n\t\t\tif (arch !== \"x64\" && arch !== \"arm64\") return;\n\n\t\t\t// Dynamic require so non-Windows and bundled/browser paths never load the\n\t\t\t// native helper. In the npm package native/ is next to dist/; in compiled\n\t\t\t// binary archives native/ is copied next to the executable.\n\t\t\tconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\t\t\tconst nativePath = path.join(\"native\", \"win32\", \"prebuilds\", `win32-${arch}`, \"win32-console-mode.node\");\n\t\t\tconst candidates = [\n\t\t\t\tpath.join(moduleDir, \"..\", nativePath),\n\t\t\t\tpath.join(moduleDir, nativePath),\n\t\t\t\tpath.join(process.env.GRIP_EMBEDDED_ASSET_DIR || path.dirname(process.execPath), nativePath),\n\t\t\t];\n\t\t\tfor (const modulePath of candidates) {\n\t\t\t\ttry {\n\t\t\t\t\tconst helper = cjsRequire(modulePath) as { enableVirtualTerminalInput?: () => boolean };\n\t\t\t\t\thelper.enableVirtualTerminalInput?.();\n\t\t\t\t\treturn;\n\t\t\t\t} catch {\n\t\t\t\t\t// Try the next possible packaging location.\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Native helper not available — Shift+Tab won't be distinguishable from Tab.\n\t\t}\n\t}\n\n\tasync drainInput(maxMs = 1000, idleMs = 50): Promise<void> {\n\t\tconst shouldDisableKittyProtocol =\n\t\t\tthis.keyboardProtocolPushed || this._kittyProtocolActive || this.keyboardProtocolNegotiationPending;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\tif (shouldDisableKittyProtocol) {\n\t\t\t// Disable Kitty keyboard protocol first so any late key releases\n\t\t\t// do not generate new Kitty escape sequences.\n\t\t\tprocess.stdout.write(\"\\x1b[<u\");\n\t\t\tthis.keyboardProtocolPushed = false;\n\t\t\tthis._kittyProtocolActive = false;\n\t\t\tsetKittyProtocolActive(false);\n\t\t}\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tif (this._modifyOtherKeysActive) {\n\t\t\tprocess.stdout.write(\"\\x1b[>4;0m\");\n\t\t\tthis._modifyOtherKeysActive = false;\n\t\t}\n\n\t\tconst previousHandler = this.inputHandler;\n\t\tthis.inputHandler = undefined;\n\n\t\tlet lastDataTime = Date.now();\n\t\tconst onData = () => {\n\t\t\tlastDataTime = Date.now();\n\t\t};\n\n\t\tprocess.stdin.on(\"data\", onData);\n\t\tconst endTime = Date.now() + maxMs;\n\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst now = Date.now();\n\t\t\t\tconst timeLeft = endTime - now;\n\t\t\t\tif (timeLeft <= 0) break;\n\t\t\t\tif (now - lastDataTime >= idleMs) break;\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, Math.min(idleMs, timeLeft)));\n\t\t\t}\n\t\t} finally {\n\t\t\tprocess.stdin.removeListener(\"data\", onData);\n\t\t\tthis.inputHandler = previousHandler;\n\t\t}\n\t}\n\n\tstop(): void {\n\t\tthis.started = false;\n\t\tif (this.clearProgressInterval()) {\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE);\n\t\t}\n\n\t\t// Disable bracketed paste mode\n\t\tprocess.stdout.write(\"\\x1b[?2004l\");\n\n\t\tconst shouldDisableKittyProtocol =\n\t\t\tthis.keyboardProtocolPushed || this._kittyProtocolActive || this.keyboardProtocolNegotiationPending;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\n\t\t// Disable Kitty keyboard protocol if not already done by drainInput()\n\t\tif (shouldDisableKittyProtocol) {\n\t\t\tprocess.stdout.write(\"\\x1b[<u\");\n\t\t\tthis.keyboardProtocolPushed = false;\n\t\t\tthis._kittyProtocolActive = false;\n\t\t\tsetKittyProtocolActive(false);\n\t\t}\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tif (this._modifyOtherKeysActive) {\n\t\t\tprocess.stdout.write(\"\\x1b[>4;0m\");\n\t\t\tthis._modifyOtherKeysActive = false;\n\t\t}\n\n\t\t// Clean up StdinBuffer\n\t\tif (this.stdinBuffer) {\n\t\t\tthis.stdinBuffer.destroy();\n\t\t\tthis.stdinBuffer = undefined;\n\t\t}\n\n\t\t// Remove event handlers\n\t\tif (this.stdinDataHandler) {\n\t\t\tprocess.stdin.removeListener(\"data\", this.stdinDataHandler);\n\t\t\tthis.stdinDataHandler = undefined;\n\t\t}\n\t\tthis.inputHandler = undefined;\n\t\tif (this.resizeHandler) {\n\t\t\tprocess.stdout.removeListener(\"resize\", this.resizeHandler);\n\t\t\tthis.resizeHandler = undefined;\n\t\t}\n\n\t\t// Pause stdin to prevent any buffered input (e.g., Ctrl+D) from being\n\t\t// re-interpreted after raw mode is disabled. This fixes a race condition\n\t\t// where Ctrl+D could close the parent shell over SSH.\n\t\tprocess.stdin.pause();\n\n\t\t// Restore raw mode state\n\t\tif (process.stdin.setRawMode) {\n\t\t\tprocess.stdin.setRawMode(this.wasRaw);\n\t\t}\n\t}\n\n\twrite(data: string): void {\n\t\tprocess.stdout.write(data);\n\t\tif (this.writeLogPath) {\n\t\t\ttry {\n\t\t\t\tfs.appendFileSync(this.writeLogPath, data, { encoding: \"utf8\" });\n\t\t\t} catch {\n\t\t\t\t// Ignore logging errors\n\t\t\t}\n\t\t}\n\t}\n\n\tget columns(): number {\n\t\treturn process.stdout.columns || Number(process.env.COLUMNS) || 80;\n\t}\n\n\tget rows(): number {\n\t\treturn process.stdout.rows || Number(process.env.LINES) || 24;\n\t}\n\n\tmoveBy(lines: number): void {\n\t\tif (lines > 0) {\n\t\t\t// Move down\n\t\t\tprocess.stdout.write(`\\x1b[${lines}B`);\n\t\t} else if (lines < 0) {\n\t\t\t// Move up\n\t\t\tprocess.stdout.write(`\\x1b[${-lines}A`);\n\t\t}\n\t\t// lines === 0: no movement\n\t}\n\n\thideCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[?25l\");\n\t}\n\n\tshowCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[?25h\");\n\t}\n\n\tclearLine(): void {\n\t\tprocess.stdout.write(\"\\x1b[K\");\n\t}\n\n\tclearFromCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[J\");\n\t}\n\n\tclearScreen(): void {\n\t\tprocess.stdout.write(\"\\x1b[2J\\x1b[H\"); // Clear screen and move to home (1,1)\n\t}\n\n\tsetTitle(title: string): void {\n\t\t// OSC 0;title BEL - set terminal window title\n\t\tprocess.stdout.write(`\\x1b]0;${sanitizeTerminalControlPayload(title)}\\x07`);\n\t}\n\n\tsetProgress(active: boolean): void {\n\t\tif (active) {\n\t\t\t// OSC 9;4;3 - indeterminate progress\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE);\n\t\t\tif (!this.progressInterval) {\n\t\t\t\tthis.progressInterval = setInterval(() => {\n\t\t\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE);\n\t\t\t\t}, TERMINAL_PROGRESS_KEEPALIVE_MS);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.clearProgressInterval();\n\t\t\t// OSC 9;4;0 - clear progress\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE);\n\t\t}\n\t}\n\n\tprivate clearProgressInterval(): boolean {\n\t\tif (!this.progressInterval) return false;\n\t\tclearInterval(this.progressInterval);\n\t\tthis.progressInterval = undefined;\n\t\treturn true;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tui-main-screen.d.ts","sourceRoot":"","sources":["../src/tui-main-screen.ts"],"names":[],"mappings":"AAGA,OAAO,EAA+B,KAAK,GAAG,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAkE/F,MAAM,WAAW,wBAAwB;IACxC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;CAC5B;AAED,sFAAsF;AACtF,qBAAa,aAAc,SAAQ,OAAQ,YAAW,GAAG;IACxD,QAAQ,CAAC,IAAI,YAAsB;IACnC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,qBAAqB,CAAqB;IAClD,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,mBAAmB,CAAK;IAEhC,kBAAkB,IAAI,wBAAwB,CAU7C;IAED,kBAAkB,CAAC,KAAK,EAAE,wBAAwB,GAAG,IAAI,CASxD;IAED,UAAmB,gBAAgB,IAAI,IAAI,CAQ1C;IAED,UAAmB,kBAAkB,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,CAQpE;IAED,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,yBAAyB;IAcjC,OAAO,CAAC,gCAAgC;IAuBxC,OAAO,CAAC,wBAAwB;IAchC,OAAO,CAAC,kBAAkB;IAe1B,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,eAAe;IAiCvB,OAAO,CAAC,uBAAuB;IAwB/B,OAAO,CAAC,kBAAkB;IA0B1B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,oBAAoB;IA8C5B,OAAO,CAAC,sBAAsB;IA6B9B,OAAO,CAAC,kBAAkB;IAmC1B,OAAO,CAAC,yBAAyB;IAuCjC,OAAO,CAAC,yBAAyB;IAkEjC,SAAS,CAAC,QAAQ,IAAI,IAAI,CAczB;IAED;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;CAgC9B","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { deleteKittyImage, isImageLine } from \"./terminal-image.ts\";\nimport { type RenderedCursorPosition, type TUI, TuiBase, type TuiStopOptions } from \"./tui.ts\";\nimport { visibleWidth } from \"./utils.ts\";\n\nconst KITTY_SEQUENCE_PREFIX = \"\\x1b_G\";\n\ninterface KittyImageHeader {\n\tids: number[];\n\trows: number;\n}\n\ninterface ChangedLineRange {\n\tfirstChanged: number;\n\tlastChanged: number;\n}\n\ninterface ChangedContentRange extends ChangedLineRange {\n\tappendStart: boolean;\n}\n\ninterface MainScreenRenderFrame {\n\twidth: number;\n\theight: number;\n\twidthChanged: boolean;\n\theightChanged: boolean;\n\tnewLines: string[];\n\tcursorPosition: RenderedCursorPosition | null;\n\tpreviousViewportTop: number;\n}\n\ninterface ChangedLinesRenderResult {\n\tbuffer: string;\n\trenderEnd: number;\n}\n\nfunction parseKittyImageHeader(line: string): KittyImageHeader | undefined {\n\tconst sequenceStart = line.indexOf(KITTY_SEQUENCE_PREFIX);\n\tif (sequenceStart === -1) return undefined;\n\tconst paramsStart = sequenceStart + KITTY_SEQUENCE_PREFIX.length;\n\tconst paramsEnd = line.indexOf(\";\", paramsStart);\n\tif (paramsEnd === -1) return undefined;\n\n\tconst ids: number[] = [];\n\tlet rows = 1;\n\tfor (const param of line.slice(paramsStart, paramsEnd).split(\",\")) {\n\t\tconst [key, value] = param.split(\"=\", 2);\n\t\tif (value === undefined) continue;\n\t\tconst numberValue = Number(value);\n\t\tif (!Number.isInteger(numberValue) || numberValue <= 0 || numberValue > 0xffffffff) continue;\n\t\tif (key === \"i\") ids.push(numberValue);\n\t\telse if (key === \"r\") rows = numberValue;\n\t}\n\treturn { ids, rows };\n}\n\nfunction extractKittyImageIds(line: string): number[] {\n\treturn parseKittyImageHeader(line)?.ids ?? [];\n}\n\nfunction extractKittyImageRows(line: string): number {\n\treturn parseKittyImageHeader(line)?.rows ?? 1;\n}\n\nfunction isTermuxSession(): boolean {\n\treturn Boolean(process.env.TERMUX_VERSION);\n}\n\nexport interface TuiMainScreenRenderState {\n\tpreviousLines: string[];\n\tpreviousWidth: number;\n\tpreviousHeight: number;\n\tcursorRow: number;\n\thardwareCursorRow: number;\n\tmaxLinesRendered: number;\n\tpreviousViewportTop: number;\n}\n\n/** TUI implementation that renders into the terminal's main screen and scrollback. */\nexport class TuiMainScreen extends TuiBase implements TUI {\n\treadonly mode = \"regular\" as const;\n\tprivate previousLines: string[] = [];\n\tprivate previousKittyImageIds = new Set<number>();\n\tprivate previousWidth = 0;\n\tprivate previousHeight = 0;\n\tprivate cursorRow = 0;\n\tprivate hardwareCursorRow = 0;\n\tprivate maxLinesRendered = 0;\n\tprivate previousViewportTop = 0;\n\n\tcaptureRenderState(): TuiMainScreenRenderState {\n\t\treturn {\n\t\t\tpreviousLines: [...this.previousLines],\n\t\t\tpreviousWidth: this.previousWidth,\n\t\t\tpreviousHeight: this.previousHeight,\n\t\t\tcursorRow: this.cursorRow,\n\t\t\thardwareCursorRow: this.hardwareCursorRow,\n\t\t\tmaxLinesRendered: this.maxLinesRendered,\n\t\t\tpreviousViewportTop: this.previousViewportTop,\n\t\t};\n\t}\n\n\trestoreRenderState(state: TuiMainScreenRenderState): void {\n\t\tthis.previousLines = state.previousLines.map((line) => (isImageLine(line) ? \"\" : line));\n\t\tthis.previousKittyImageIds = new Set();\n\t\tthis.previousWidth = state.previousWidth;\n\t\tthis.previousHeight = state.previousHeight;\n\t\tthis.cursorRow = state.cursorRow;\n\t\tthis.hardwareCursorRow = state.hardwareCursorRow;\n\t\tthis.maxLinesRendered = state.maxLinesRendered;\n\t\tthis.previousViewportTop = state.previousViewportTop;\n\t}\n\n\tprotected override resetRenderState(): void {\n\t\tthis.previousLines = [];\n\t\tthis.previousWidth = -1;\n\t\tthis.previousHeight = -1;\n\t\tthis.cursorRow = 0;\n\t\tthis.hardwareCursorRow = 0;\n\t\tthis.maxLinesRendered = 0;\n\t\tthis.previousViewportTop = 0;\n\t}\n\n\tprotected override beforeTerminalStop(options?: TuiStopOptions): void {\n\t\tif (options?.preserveScreen || this.previousLines.length === 0) return;\n\t\tthis.terminal.write(\" \");\n\t\tconst targetRow = this.previousLines.length;\n\t\tconst lineDiff = targetRow - this.hardwareCursorRow;\n\t\tif (lineDiff > 0) this.terminal.write(`\\x1b[${lineDiff}B`);\n\t\telse if (lineDiff < 0) this.terminal.write(`\\x1b[${-lineDiff}A`);\n\t\tthis.terminal.write(\"\\r\\n\");\n\t}\n\n\tprivate collectKittyImageIds(lines: string[]): Set<number> {\n\t\tconst ids = new Set<number>();\n\t\tfor (const line of lines) {\n\t\t\tfor (const id of extractKittyImageIds(line)) {\n\t\t\t\tids.add(id);\n\t\t\t}\n\t\t}\n\t\treturn ids;\n\t}\n\n\tprivate deleteKittyImages(ids: Iterable<number>): string {\n\t\tlet buffer = \"\";\n\t\tfor (const id of ids) {\n\t\t\tbuffer += deleteKittyImage(id);\n\t\t}\n\t\treturn buffer;\n\t}\n\n\tprivate getKittyImageReservedRows(lines: string[], index: number, maxIndex = lines.length - 1): number {\n\t\tconst rows = extractKittyImageRows(lines[index] ?? \"\");\n\t\tif (rows <= 1) return 1;\n\n\t\tconst maxRows = Math.min(rows, maxIndex - index + 1, lines.length - index);\n\t\tlet reservedRows = 1;\n\t\twhile (reservedRows < maxRows) {\n\t\t\tconst line = lines[index + reservedRows] ?? \"\";\n\t\t\tif (isImageLine(line) || visibleWidth(line) > 0) break;\n\t\t\treservedRows++;\n\t\t}\n\t\treturn reservedRows;\n\t}\n\n\tprivate expandChangedRangeForKittyImages(\n\t\tfirstChanged: number,\n\t\tlastChanged: number,\n\t\tnewLines: string[],\n\t): ChangedLineRange {\n\t\tlet expandedFirstChanged = firstChanged;\n\t\tlet expandedLastChanged = lastChanged;\n\t\tconst expandForLines = (lines: string[]): void => {\n\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\tif (extractKittyImageIds(lines[i]).length === 0) continue;\n\t\t\t\tconst blockEnd = i + this.getKittyImageReservedRows(lines, i) - 1;\n\t\t\t\tif (i >= firstChanged || (i <= lastChanged && blockEnd >= firstChanged)) {\n\t\t\t\t\texpandedFirstChanged = Math.min(expandedFirstChanged, i);\n\t\t\t\t\texpandedLastChanged = Math.max(expandedLastChanged, blockEnd);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\texpandForLines(this.previousLines);\n\t\texpandForLines(newLines);\n\t\treturn { firstChanged: expandedFirstChanged, lastChanged: expandedLastChanged };\n\t}\n\n\tprivate deleteChangedKittyImages(firstChanged: number, lastChanged: number): string {\n\t\tif (firstChanged < 0 || lastChanged < firstChanged) return \"\";\n\n\t\tconst ids = new Set<number>();\n\t\tconst maxLine = Math.min(lastChanged, this.previousLines.length - 1);\n\t\tfor (let i = firstChanged; i <= maxLine; i++) {\n\t\t\tfor (const id of extractKittyImageIds(this.previousLines[i] ?? \"\")) {\n\t\t\t\tids.add(id);\n\t\t\t}\n\t\t}\n\n\t\treturn this.deleteKittyImages(ids);\n\t}\n\n\tprivate prepareRenderFrame(): MainScreenRenderFrame {\n\t\tconst width = this.terminal.columns;\n\t\tconst height = this.terminal.rows;\n\t\tconst widthChanged = this.previousWidth !== 0 && this.previousWidth !== width;\n\t\tconst heightChanged = this.previousHeight !== 0 && this.previousHeight !== height;\n\t\tconst previousBufferLength = this.previousHeight > 0 ? this.previousViewportTop + this.previousHeight : height;\n\t\tconst previousViewportTop = heightChanged ? Math.max(0, previousBufferLength - height) : this.previousViewportTop;\n\n\t\tlet newLines = this.render(width);\n\t\tif (this.hasOverlayEntries) newLines = this.compositeOverlays(newLines, width, height);\n\t\tconst cursorPosition = this.extractCursorPosition(newLines, height);\n\t\tnewLines = this.applyLineResets(newLines);\n\t\treturn { width, height, widthChanged, heightChanged, newLines, cursorPosition, previousViewportTop };\n\t}\n\n\tprivate getLineDiff(\n\t\ttargetRow: number,\n\t\thardwareCursorRow: number,\n\t\tpreviousViewportTop: number,\n\t\tviewportTop: number,\n\t): number {\n\t\tconst currentScreenRow = hardwareCursorRow - previousViewportTop;\n\t\tconst targetScreenRow = targetRow - viewportTop;\n\t\treturn targetScreenRow - currentScreenRow;\n\t}\n\n\tprivate logFullRedraw(frame: MainScreenRenderFrame, reason: string): void {\n\t\tif (process.env.GRIP_DEBUG_REDRAW !== \"1\") return;\n\t\tconst logPath = path.join(this.logDirectory, \"grip-debug.log\");\n\t\tconst message = `[${new Date().toISOString()}] fullRender: ${reason} (prev=${this.previousLines.length}, new=${frame.newLines.length}, height=${frame.height})\\n`;\n\t\tfs.mkdirSync(path.dirname(logPath), { recursive: true });\n\t\tfs.appendFileSync(logPath, message);\n\t}\n\n\tprivate renderFullFrame(frame: MainScreenRenderFrame, clear: boolean): void {\n\t\tthis.fullRedrawCount += 1;\n\t\tlet buffer = \"\\x1b[?2026h\";\n\t\tif (clear) {\n\t\t\tbuffer += this.deleteKittyImages(this.previousKittyImageIds);\n\t\t\tbuffer += \"\\x1b[2J\\x1b[H\\x1b[3J\";\n\t\t}\n\t\tfor (let index = 0; index < frame.newLines.length; index++) {\n\t\t\tif (index > 0) buffer += \"\\r\\n\";\n\t\t\tconst line = frame.newLines[index];\n\t\t\tconst reservedRows = isImageLine(line) ? this.getKittyImageReservedRows(frame.newLines, index) : 1;\n\t\t\tif (reservedRows > 1 && reservedRows <= frame.height) {\n\t\t\t\tbuffer += \"\\r\\n\".repeat(reservedRows - 1);\n\t\t\t\tbuffer += `\\x1b[${reservedRows - 1}A${line}\\x1b[${reservedRows - 1}B`;\n\t\t\t\tindex += reservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbuffer += line;\n\t\t}\n\t\tbuffer += \"\\x1b[?2026l\";\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = Math.max(0, frame.newLines.length - 1);\n\t\tthis.hardwareCursorRow = this.cursorRow;\n\t\tthis.maxLinesRendered = clear ? frame.newLines.length : Math.max(this.maxLinesRendered, frame.newLines.length);\n\t\tconst bufferLength = Math.max(frame.height, frame.newLines.length);\n\t\tthis.previousViewportTop = Math.max(0, bufferLength - frame.height);\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.previousLines = frame.newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(frame.newLines);\n\t\tthis.previousWidth = frame.width;\n\t\tthis.previousHeight = frame.height;\n\t}\n\n\tprivate renderRequiredFullFrame(frame: MainScreenRenderFrame): boolean {\n\t\tif (this.previousLines.length === 0 && !frame.widthChanged && !frame.heightChanged) {\n\t\t\tthis.logFullRedraw(frame, \"first render\");\n\t\t\tthis.renderFullFrame(frame, false);\n\t\t\treturn true;\n\t\t}\n\t\tif (frame.widthChanged) {\n\t\t\tthis.logFullRedraw(frame, `terminal width changed (${this.previousWidth} -> ${frame.width})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\tif (frame.heightChanged && !isTermuxSession()) {\n\t\t\tthis.logFullRedraw(frame, `terminal height changed (${this.previousHeight} -> ${frame.height})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\tif (this.getClearOnShrink() && frame.newLines.length < this.maxLinesRendered && !this.hasOverlayEntries) {\n\t\t\tthis.logFullRedraw(frame, `clearOnShrink (maxLinesRendered=${this.maxLinesRendered})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate findChangedContent(frame: MainScreenRenderFrame): ChangedContentRange | undefined {\n\t\tlet firstChanged = -1;\n\t\tlet lastChanged = -1;\n\t\tconst maxLines = Math.max(frame.newLines.length, this.previousLines.length);\n\t\tfor (let index = 0; index < maxLines; index++) {\n\t\t\tconst oldLine = index < this.previousLines.length ? this.previousLines[index] : \"\";\n\t\t\tconst newLine = index < frame.newLines.length ? frame.newLines[index] : \"\";\n\t\t\tif (oldLine === newLine) continue;\n\t\t\tif (firstChanged === -1) firstChanged = index;\n\t\t\tlastChanged = index;\n\t\t}\n\n\t\tconst appendedLines = frame.newLines.length > this.previousLines.length;\n\t\tif (appendedLines) {\n\t\t\tif (firstChanged === -1) firstChanged = this.previousLines.length;\n\t\t\tlastChanged = frame.newLines.length - 1;\n\t\t}\n\t\tif (firstChanged === -1) return undefined;\n\n\t\tconst expanded = this.expandChangedRangeForKittyImages(firstChanged, lastChanged, frame.newLines);\n\t\treturn {\n\t\t\t...expanded,\n\t\t\tappendStart: appendedLines && expanded.firstChanged === this.previousLines.length && expanded.firstChanged > 0,\n\t\t};\n\t}\n\n\tprivate commitFrameHistory(frame: MainScreenRenderFrame, viewportTop: number): void {\n\t\tthis.previousLines = frame.newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(frame.newLines);\n\t\tthis.previousWidth = frame.width;\n\t\tthis.previousHeight = frame.height;\n\t\tthis.previousViewportTop = viewportTop;\n\t}\n\n\tprivate handleUnchangedFrame(frame: MainScreenRenderFrame): void {\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.previousViewportTop = frame.previousViewportTop;\n\t\tthis.previousHeight = frame.height;\n\t}\n\n\tprivate renderDeletedContent(frame: MainScreenRenderFrame, range: ChangedContentRange): void {\n\t\tif (this.previousLines.length <= frame.newLines.length) {\n\t\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\t\tthis.commitFrameHistory(frame, frame.previousViewportTop);\n\t\t\treturn;\n\t\t}\n\n\t\tlet buffer = \"\\x1b[?2026h\";\n\t\tbuffer += this.deleteChangedKittyImages(range.firstChanged, range.lastChanged);\n\t\tconst targetRow = Math.max(0, frame.newLines.length - 1);\n\t\tif (targetRow < frame.previousViewportTop) {\n\t\t\tthis.logFullRedraw(frame, `deleted lines moved viewport up (${targetRow} < ${frame.previousViewportTop})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\t\tconst lineDiff = this.getLineDiff(\n\t\t\ttargetRow,\n\t\t\tthis.hardwareCursorRow,\n\t\t\tframe.previousViewportTop,\n\t\t\tframe.previousViewportTop,\n\t\t);\n\t\tif (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n\t\telse if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n\t\tbuffer += \"\\r\";\n\t\tconst extraLines = this.previousLines.length - frame.newLines.length;\n\t\tif (extraLines > frame.height) {\n\t\t\tthis.logFullRedraw(frame, `extraLines > height (${extraLines} > ${frame.height})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\t\tconst clearStartOffset = frame.newLines.length === 0 ? 0 : 1;\n\t\tif (extraLines > 0 && clearStartOffset > 0) buffer += `\\x1b[${clearStartOffset}B`;\n\t\tfor (let index = 0; index < extraLines; index++) {\n\t\t\tbuffer += \"\\r\\x1b[2K\";\n\t\t\tif (index < extraLines - 1) buffer += \"\\x1b[1B\";\n\t\t}\n\t\tconst moveBack = Math.max(0, extraLines - 1 + clearStartOffset);\n\t\tif (moveBack > 0) buffer += `\\x1b[${moveBack}A`;\n\t\tbuffer += \"\\x1b[?2026l\";\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = targetRow;\n\t\tthis.hardwareCursorRow = targetRow;\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.commitFrameHistory(frame, frame.previousViewportTop);\n\t}\n\n\tprivate assertRenderedLineFits(line: string, index: number, frame: MainScreenRenderFrame): void {\n\t\tif (isImageLine(line) || visibleWidth(line) <= frame.width) return;\n\t\tconst crashLogPath = path.join(this.logDirectory, \"grip-crash.log\");\n\t\tconst crashData = [\n\t\t\t`Crash at ${new Date().toISOString()}`,\n\t\t\t`Terminal width: ${frame.width}`,\n\t\t\t`Line ${index} visible width: ${visibleWidth(line)}`,\n\t\t\t\"\",\n\t\t\t\"=== All rendered lines ===\",\n\t\t\t...frame.newLines.map(\n\t\t\t\t(renderedLine, lineIndex) => `[${lineIndex}] (w=${visibleWidth(renderedLine)}) ${renderedLine}`,\n\t\t\t),\n\t\t\t\"\",\n\t\t].join(\"\\n\");\n\t\tfs.mkdirSync(path.dirname(crashLogPath), { recursive: true });\n\t\tfs.writeFileSync(crashLogPath, crashData);\n\t\tthis.stop();\n\t\tthrow new Error(\n\t\t\t[\n\t\t\t\t`Rendered line ${index} exceeds terminal width (${visibleWidth(line)} > ${frame.width}).`,\n\t\t\t\t\"\",\n\t\t\t\t\"This is likely caused by a custom TUI component not truncating its output.\",\n\t\t\t\t\"Use visibleWidth() to measure and truncateToWidth() to truncate lines.\",\n\t\t\t\t\"\",\n\t\t\t\t`Debug log written to: ${crashLogPath}`,\n\t\t\t].join(\"\\n\"),\n\t\t);\n\t}\n\n\tprivate renderChangedLines(\n\t\tframe: MainScreenRenderFrame,\n\t\trange: ChangedContentRange,\n\t\tviewportTop: number,\n\t\tinitialBuffer: string,\n\t): ChangedLinesRenderResult | undefined {\n\t\tlet buffer = initialBuffer;\n\t\tconst renderEnd = Math.min(range.lastChanged, frame.newLines.length - 1);\n\t\tfor (let index = range.firstChanged; index <= renderEnd; index++) {\n\t\t\tif (index > range.firstChanged) buffer += \"\\r\\n\";\n\t\t\tconst line = frame.newLines[index];\n\t\t\tconst reservedRows = isImageLine(line) ? this.getKittyImageReservedRows(frame.newLines, index, renderEnd) : 1;\n\t\t\tif (reservedRows > 1) {\n\t\t\t\tconst imageStartScreenRow = index - viewportTop;\n\t\t\t\tif (imageStartScreenRow < 0 || imageStartScreenRow + reservedRows > frame.height) {\n\t\t\t\t\tthis.logFullRedraw(\n\t\t\t\t\t\tframe,\n\t\t\t\t\t\t`kitty image pre-clear would scroll (${imageStartScreenRow} + ${reservedRows} > ${frame.height})`,\n\t\t\t\t\t);\n\t\t\t\t\tthis.renderFullFrame(frame, true);\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tbuffer += \"\\x1b[2K\";\n\t\t\t\tfor (let row = 1; row < reservedRows; row++) buffer += \"\\r\\n\\x1b[2K\";\n\t\t\t\tbuffer += `\\x1b[${reservedRows - 1}A${line}\\x1b[${reservedRows - 1}B`;\n\t\t\t\tindex += reservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbuffer += \"\\x1b[2K\";\n\t\t\tthis.assertRenderedLineFits(line, index, frame);\n\t\t\tbuffer += line;\n\t\t}\n\t\treturn { buffer, renderEnd };\n\t}\n\n\tprivate writeDifferentialDebugLog(\n\t\tframe: MainScreenRenderFrame,\n\t\trange: ChangedContentRange,\n\t\tviewportTop: number,\n\t\thardwareCursorRow: number,\n\t\tlineDiff: number,\n\t\trenderEnd: number,\n\t\tfinalCursorRow: number,\n\t\tbuffer: string,\n\t): void {\n\t\tif (process.env.GRIP_TUI_DEBUG !== \"1\") return;\n\t\tconst debugDir = \"/tmp/tui\";\n\t\tfs.mkdirSync(debugDir, { recursive: true });\n\t\tconst debugPath = path.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);\n\t\tconst debugData = [\n\t\t\t`firstChanged: ${range.firstChanged}`,\n\t\t\t`viewportTop: ${viewportTop}`,\n\t\t\t`cursorRow: ${this.cursorRow}`,\n\t\t\t`height: ${frame.height}`,\n\t\t\t`lineDiff: ${lineDiff}`,\n\t\t\t`hardwareCursorRow: ${hardwareCursorRow}`,\n\t\t\t`renderEnd: ${renderEnd}`,\n\t\t\t`finalCursorRow: ${finalCursorRow}`,\n\t\t\t`cursorPos: ${JSON.stringify(frame.cursorPosition)}`,\n\t\t\t`newLines.length: ${frame.newLines.length}`,\n\t\t\t`previousLines.length: ${this.previousLines.length}`,\n\t\t\t\"\",\n\t\t\t\"=== newLines ===\",\n\t\t\tJSON.stringify(frame.newLines, null, 2),\n\t\t\t\"\",\n\t\t\t\"=== previousLines ===\",\n\t\t\tJSON.stringify(this.previousLines, null, 2),\n\t\t\t\"\",\n\t\t\t\"=== buffer ===\",\n\t\t\tJSON.stringify(buffer),\n\t\t].join(\"\\n\");\n\t\tfs.writeFileSync(debugPath, debugData);\n\t}\n\n\tprivate renderDifferentialContent(frame: MainScreenRenderFrame, range: ChangedContentRange): void {\n\t\tif (range.firstChanged < frame.previousViewportTop) {\n\t\t\tthis.logFullRedraw(frame, `firstChanged < viewportTop (${range.firstChanged} < ${frame.previousViewportTop})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\n\t\tlet previousViewportTop = frame.previousViewportTop;\n\t\tlet viewportTop = previousViewportTop;\n\t\tlet hardwareCursorRow = this.hardwareCursorRow;\n\t\tlet buffer = `\\x1b[?2026h${this.deleteChangedKittyImages(range.firstChanged, range.lastChanged)}`;\n\t\tconst previousViewportBottom = previousViewportTop + frame.height - 1;\n\t\tconst moveTargetRow = range.appendStart ? range.firstChanged - 1 : range.firstChanged;\n\t\tif (moveTargetRow > previousViewportBottom) {\n\t\t\tconst currentScreenRow = Math.max(0, Math.min(frame.height - 1, hardwareCursorRow - previousViewportTop));\n\t\t\tconst moveToBottom = frame.height - 1 - currentScreenRow;\n\t\t\tif (moveToBottom > 0) buffer += `\\x1b[${moveToBottom}B`;\n\t\t\tconst scroll = moveTargetRow - previousViewportBottom;\n\t\t\tbuffer += \"\\r\\n\".repeat(scroll);\n\t\t\tpreviousViewportTop += scroll;\n\t\t\tviewportTop += scroll;\n\t\t\thardwareCursorRow = moveTargetRow;\n\t\t}\n\n\t\tconst lineDiff = this.getLineDiff(moveTargetRow, hardwareCursorRow, previousViewportTop, viewportTop);\n\t\tif (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n\t\telse if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n\t\tbuffer += range.appendStart ? \"\\r\\n\" : \"\\r\";\n\n\t\tconst changedLines = this.renderChangedLines(frame, range, viewportTop, buffer);\n\t\tif (!changedLines) return;\n\t\tbuffer = changedLines.buffer;\n\t\tlet finalCursorRow = changedLines.renderEnd;\n\t\tif (this.previousLines.length > frame.newLines.length) {\n\t\t\tif (changedLines.renderEnd < frame.newLines.length - 1) {\n\t\t\t\tconst moveDown = frame.newLines.length - 1 - changedLines.renderEnd;\n\t\t\t\tbuffer += `\\x1b[${moveDown}B`;\n\t\t\t\tfinalCursorRow = frame.newLines.length - 1;\n\t\t\t}\n\t\t\tconst extraLines = this.previousLines.length - frame.newLines.length;\n\t\t\tfor (let index = frame.newLines.length; index < this.previousLines.length; index++) {\n\t\t\t\tbuffer += \"\\r\\n\\x1b[2K\";\n\t\t\t}\n\t\t\tbuffer += `\\x1b[${extraLines}A`;\n\t\t}\n\t\tbuffer += \"\\x1b[?2026l\";\n\n\t\tthis.writeDifferentialDebugLog(\n\t\t\tframe,\n\t\t\trange,\n\t\t\tviewportTop,\n\t\t\thardwareCursorRow,\n\t\t\tlineDiff,\n\t\t\tchangedLines.renderEnd,\n\t\t\tfinalCursorRow,\n\t\t\tbuffer,\n\t\t);\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = Math.max(0, frame.newLines.length - 1);\n\t\tthis.hardwareCursorRow = finalCursorRow;\n\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, frame.newLines.length);\n\t\tconst committedViewportTop = Math.max(previousViewportTop, finalCursorRow - frame.height + 1);\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.commitFrameHistory(frame, committedViewportTop);\n\t}\n\n\tprotected doRender(): void {\n\t\tif (this.stopped) return;\n\t\tconst frame = this.prepareRenderFrame();\n\t\tif (this.renderRequiredFullFrame(frame)) return;\n\t\tconst changedContent = this.findChangedContent(frame);\n\t\tif (!changedContent) {\n\t\t\tthis.handleUnchangedFrame(frame);\n\t\t\treturn;\n\t\t}\n\t\tif (changedContent.firstChanged >= frame.newLines.length) {\n\t\t\tthis.renderDeletedContent(frame, changedContent);\n\t\t\treturn;\n\t\t}\n\t\tthis.renderDifferentialContent(frame, changedContent);\n\t}\n\n\t/**\n\t * Position the hardware cursor for IME candidate window.\n\t * @param cursorPos The cursor position extracted from rendered output, or null\n\t * @param totalLines Total number of rendered lines\n\t */\n\tprivate positionHardwareCursor(cursorPos: RenderedCursorPosition | null, totalLines: number): void {\n\t\tif (!cursorPos || totalLines <= 0) {\n\t\t\tthis.terminal.hideCursor();\n\t\t\treturn;\n\t\t}\n\n\t\t// Clamp cursor position to valid range\n\t\tconst targetRow = Math.max(0, Math.min(cursorPos.row, totalLines - 1));\n\t\tconst targetCol = Math.max(0, cursorPos.col);\n\n\t\t// Move cursor from current position to target\n\t\tconst rowDelta = targetRow - this.hardwareCursorRow;\n\t\tlet buffer = \"\";\n\t\tif (rowDelta > 0) {\n\t\t\tbuffer += `\\x1b[${rowDelta}B`; // Move down\n\t\t} else if (rowDelta < 0) {\n\t\t\tbuffer += `\\x1b[${-rowDelta}A`; // Move up\n\t\t}\n\t\t// Move to absolute column (1-indexed)\n\t\tbuffer += `\\x1b[${targetCol + 1}G`;\n\n\t\tif (buffer) {\n\t\t\tthis.terminal.write(buffer);\n\t\t}\n\n\t\tthis.hardwareCursorRow = targetRow;\n\t\tif (this.getShowHardwareCursor()) {\n\t\t\tthis.terminal.showCursor();\n\t\t} else {\n\t\t\tthis.terminal.hideCursor();\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"tui-main-screen.d.ts","sourceRoot":"","sources":["../src/tui-main-screen.ts"],"names":[],"mappings":"AAGA,OAAO,EAA+B,KAAK,GAAG,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAmE/F,MAAM,WAAW,wBAAwB;IACxC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;CAC5B;AAED,sFAAsF;AACtF,qBAAa,aAAc,SAAQ,OAAQ,YAAW,GAAG;IACxD,QAAQ,CAAC,IAAI,YAAsB;IACnC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,qBAAqB,CAAqB;IAClD,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,mBAAmB,CAAK;IAEhC,kBAAkB,IAAI,wBAAwB,CAU7C;IAED,kBAAkB,CAAC,KAAK,EAAE,wBAAwB,GAAG,IAAI,CASxD;IAED,UAAmB,gBAAgB,IAAI,IAAI,CAQ1C;IAED,UAAmB,kBAAkB,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,CAQpE;IAED,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,yBAAyB;IAcjC,OAAO,CAAC,gCAAgC;IAuBxC,OAAO,CAAC,wBAAwB;IAchC,OAAO,CAAC,kBAAkB;IAiB1B,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,eAAe;IAiCvB,OAAO,CAAC,uBAAuB;IAwB/B,OAAO,CAAC,kBAAkB;IA0B1B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,oBAAoB;IA8C5B,OAAO,CAAC,sBAAsB;IA6B9B,OAAO,CAAC,kBAAkB;IAmC1B,OAAO,CAAC,yBAAyB;IAuCjC,OAAO,CAAC,yBAAyB;IAkEjC,SAAS,CAAC,QAAQ,IAAI,IAAI,CAczB;IAED;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;CAgC9B","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { deleteKittyImage, isImageLine } from \"./terminal-image.ts\";\nimport { type RenderedCursorPosition, type TUI, TuiBase, type TuiStopOptions } from \"./tui.ts\";\nimport { visibleWidth } from \"./utils.ts\";\n\nconst KITTY_SEQUENCE_PREFIX = \"\\x1b_G\";\nconst OSC133_ZONE_PREFIX = /^(?:\\x1b\\]133;[ABC](?:\\x07|\\x1b\\\\))+/;\n\ninterface KittyImageHeader {\n\tids: number[];\n\trows: number;\n}\n\ninterface ChangedLineRange {\n\tfirstChanged: number;\n\tlastChanged: number;\n}\n\ninterface ChangedContentRange extends ChangedLineRange {\n\tappendStart: boolean;\n}\n\ninterface MainScreenRenderFrame {\n\twidth: number;\n\theight: number;\n\twidthChanged: boolean;\n\theightChanged: boolean;\n\tnewLines: string[];\n\tcursorPosition: RenderedCursorPosition | null;\n\tpreviousViewportTop: number;\n}\n\ninterface ChangedLinesRenderResult {\n\tbuffer: string;\n\trenderEnd: number;\n}\n\nfunction parseKittyImageHeader(line: string): KittyImageHeader | undefined {\n\tconst sequenceStart = line.indexOf(KITTY_SEQUENCE_PREFIX);\n\tif (sequenceStart === -1) return undefined;\n\tconst paramsStart = sequenceStart + KITTY_SEQUENCE_PREFIX.length;\n\tconst paramsEnd = line.indexOf(\";\", paramsStart);\n\tif (paramsEnd === -1) return undefined;\n\n\tconst ids: number[] = [];\n\tlet rows = 1;\n\tfor (const param of line.slice(paramsStart, paramsEnd).split(\",\")) {\n\t\tconst [key, value] = param.split(\"=\", 2);\n\t\tif (value === undefined) continue;\n\t\tconst numberValue = Number(value);\n\t\tif (!Number.isInteger(numberValue) || numberValue <= 0 || numberValue > 0xffffffff) continue;\n\t\tif (key === \"i\") ids.push(numberValue);\n\t\telse if (key === \"r\") rows = numberValue;\n\t}\n\treturn { ids, rows };\n}\n\nfunction extractKittyImageIds(line: string): number[] {\n\treturn parseKittyImageHeader(line)?.ids ?? [];\n}\n\nfunction extractKittyImageRows(line: string): number {\n\treturn parseKittyImageHeader(line)?.rows ?? 1;\n}\n\nfunction isTermuxSession(): boolean {\n\treturn Boolean(process.env.TERMUX_VERSION);\n}\n\nexport interface TuiMainScreenRenderState {\n\tpreviousLines: string[];\n\tpreviousWidth: number;\n\tpreviousHeight: number;\n\tcursorRow: number;\n\thardwareCursorRow: number;\n\tmaxLinesRendered: number;\n\tpreviousViewportTop: number;\n}\n\n/** TUI implementation that renders into the terminal's main screen and scrollback. */\nexport class TuiMainScreen extends TuiBase implements TUI {\n\treadonly mode = \"regular\" as const;\n\tprivate previousLines: string[] = [];\n\tprivate previousKittyImageIds = new Set<number>();\n\tprivate previousWidth = 0;\n\tprivate previousHeight = 0;\n\tprivate cursorRow = 0;\n\tprivate hardwareCursorRow = 0;\n\tprivate maxLinesRendered = 0;\n\tprivate previousViewportTop = 0;\n\n\tcaptureRenderState(): TuiMainScreenRenderState {\n\t\treturn {\n\t\t\tpreviousLines: [...this.previousLines],\n\t\t\tpreviousWidth: this.previousWidth,\n\t\t\tpreviousHeight: this.previousHeight,\n\t\t\tcursorRow: this.cursorRow,\n\t\t\thardwareCursorRow: this.hardwareCursorRow,\n\t\t\tmaxLinesRendered: this.maxLinesRendered,\n\t\t\tpreviousViewportTop: this.previousViewportTop,\n\t\t};\n\t}\n\n\trestoreRenderState(state: TuiMainScreenRenderState): void {\n\t\tthis.previousLines = state.previousLines.map((line) => (isImageLine(line) ? \"\" : line));\n\t\tthis.previousKittyImageIds = new Set();\n\t\tthis.previousWidth = state.previousWidth;\n\t\tthis.previousHeight = state.previousHeight;\n\t\tthis.cursorRow = state.cursorRow;\n\t\tthis.hardwareCursorRow = state.hardwareCursorRow;\n\t\tthis.maxLinesRendered = state.maxLinesRendered;\n\t\tthis.previousViewportTop = state.previousViewportTop;\n\t}\n\n\tprotected override resetRenderState(): void {\n\t\tthis.previousLines = [];\n\t\tthis.previousWidth = -1;\n\t\tthis.previousHeight = -1;\n\t\tthis.cursorRow = 0;\n\t\tthis.hardwareCursorRow = 0;\n\t\tthis.maxLinesRendered = 0;\n\t\tthis.previousViewportTop = 0;\n\t}\n\n\tprotected override beforeTerminalStop(options?: TuiStopOptions): void {\n\t\tif (options?.preserveScreen || this.previousLines.length === 0) return;\n\t\tthis.terminal.write(\" \");\n\t\tconst targetRow = this.previousLines.length;\n\t\tconst lineDiff = targetRow - this.hardwareCursorRow;\n\t\tif (lineDiff > 0) this.terminal.write(`\\x1b[${lineDiff}B`);\n\t\telse if (lineDiff < 0) this.terminal.write(`\\x1b[${-lineDiff}A`);\n\t\tthis.terminal.write(\"\\r\\n\");\n\t}\n\n\tprivate collectKittyImageIds(lines: string[]): Set<number> {\n\t\tconst ids = new Set<number>();\n\t\tfor (const line of lines) {\n\t\t\tfor (const id of extractKittyImageIds(line)) {\n\t\t\t\tids.add(id);\n\t\t\t}\n\t\t}\n\t\treturn ids;\n\t}\n\n\tprivate deleteKittyImages(ids: Iterable<number>): string {\n\t\tlet buffer = \"\";\n\t\tfor (const id of ids) {\n\t\t\tbuffer += deleteKittyImage(id);\n\t\t}\n\t\treturn buffer;\n\t}\n\n\tprivate getKittyImageReservedRows(lines: string[], index: number, maxIndex = lines.length - 1): number {\n\t\tconst rows = extractKittyImageRows(lines[index] ?? \"\");\n\t\tif (rows <= 1) return 1;\n\n\t\tconst maxRows = Math.min(rows, maxIndex - index + 1, lines.length - index);\n\t\tlet reservedRows = 1;\n\t\twhile (reservedRows < maxRows) {\n\t\t\tconst line = lines[index + reservedRows] ?? \"\";\n\t\t\tif (isImageLine(line) || visibleWidth(line) > 0) break;\n\t\t\treservedRows++;\n\t\t}\n\t\treturn reservedRows;\n\t}\n\n\tprivate expandChangedRangeForKittyImages(\n\t\tfirstChanged: number,\n\t\tlastChanged: number,\n\t\tnewLines: string[],\n\t): ChangedLineRange {\n\t\tlet expandedFirstChanged = firstChanged;\n\t\tlet expandedLastChanged = lastChanged;\n\t\tconst expandForLines = (lines: string[]): void => {\n\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\tif (extractKittyImageIds(lines[i]).length === 0) continue;\n\t\t\t\tconst blockEnd = i + this.getKittyImageReservedRows(lines, i) - 1;\n\t\t\t\tif (i >= firstChanged || (i <= lastChanged && blockEnd >= firstChanged)) {\n\t\t\t\t\texpandedFirstChanged = Math.min(expandedFirstChanged, i);\n\t\t\t\t\texpandedLastChanged = Math.max(expandedLastChanged, blockEnd);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\texpandForLines(this.previousLines);\n\t\texpandForLines(newLines);\n\t\treturn { firstChanged: expandedFirstChanged, lastChanged: expandedLastChanged };\n\t}\n\n\tprivate deleteChangedKittyImages(firstChanged: number, lastChanged: number): string {\n\t\tif (firstChanged < 0 || lastChanged < firstChanged) return \"\";\n\n\t\tconst ids = new Set<number>();\n\t\tconst maxLine = Math.min(lastChanged, this.previousLines.length - 1);\n\t\tfor (let i = firstChanged; i <= maxLine; i++) {\n\t\t\tfor (const id of extractKittyImageIds(this.previousLines[i] ?? \"\")) {\n\t\t\t\tids.add(id);\n\t\t\t}\n\t\t}\n\n\t\treturn this.deleteKittyImages(ids);\n\t}\n\n\tprivate prepareRenderFrame(): MainScreenRenderFrame {\n\t\tconst width = this.terminal.columns;\n\t\tconst height = this.terminal.rows;\n\t\tconst widthChanged = this.previousWidth !== 0 && this.previousWidth !== width;\n\t\tconst heightChanged = this.previousHeight !== 0 && this.previousHeight !== height;\n\t\tconst previousBufferLength = this.previousHeight > 0 ? this.previousViewportTop + this.previousHeight : height;\n\t\tconst previousViewportTop = heightChanged ? Math.max(0, previousBufferLength - height) : this.previousViewportTop;\n\n\t\tlet newLines = this.render(width);\n\t\tif (this.hasOverlayEntries) newLines = this.compositeOverlays(newLines, width, height);\n\t\tconst cursorPosition = this.extractCursorPosition(newLines, height);\n\t\t// Preserve component zone markers for alt-screen navigation, but do not emit\n\t\t// them here: terminals draw their own gutter indicators for OSC 133.\n\t\tnewLines = this.applyLineResets(newLines.map((line) => line.replace(OSC133_ZONE_PREFIX, \"\")));\n\t\treturn { width, height, widthChanged, heightChanged, newLines, cursorPosition, previousViewportTop };\n\t}\n\n\tprivate getLineDiff(\n\t\ttargetRow: number,\n\t\thardwareCursorRow: number,\n\t\tpreviousViewportTop: number,\n\t\tviewportTop: number,\n\t): number {\n\t\tconst currentScreenRow = hardwareCursorRow - previousViewportTop;\n\t\tconst targetScreenRow = targetRow - viewportTop;\n\t\treturn targetScreenRow - currentScreenRow;\n\t}\n\n\tprivate logFullRedraw(frame: MainScreenRenderFrame, reason: string): void {\n\t\tif (process.env.GRIP_DEBUG_REDRAW !== \"1\") return;\n\t\tconst logPath = path.join(this.logDirectory, \"grip-debug.log\");\n\t\tconst message = `[${new Date().toISOString()}] fullRender: ${reason} (prev=${this.previousLines.length}, new=${frame.newLines.length}, height=${frame.height})\\n`;\n\t\tfs.mkdirSync(path.dirname(logPath), { recursive: true });\n\t\tfs.appendFileSync(logPath, message);\n\t}\n\n\tprivate renderFullFrame(frame: MainScreenRenderFrame, clear: boolean): void {\n\t\tthis.fullRedrawCount += 1;\n\t\tlet buffer = \"\\x1b[?2026h\";\n\t\tif (clear) {\n\t\t\tbuffer += this.deleteKittyImages(this.previousKittyImageIds);\n\t\t\tbuffer += \"\\x1b[2J\\x1b[H\\x1b[3J\";\n\t\t}\n\t\tfor (let index = 0; index < frame.newLines.length; index++) {\n\t\t\tif (index > 0) buffer += \"\\r\\n\";\n\t\t\tconst line = frame.newLines[index];\n\t\t\tconst reservedRows = isImageLine(line) ? this.getKittyImageReservedRows(frame.newLines, index) : 1;\n\t\t\tif (reservedRows > 1 && reservedRows <= frame.height) {\n\t\t\t\tbuffer += \"\\r\\n\".repeat(reservedRows - 1);\n\t\t\t\tbuffer += `\\x1b[${reservedRows - 1}A${line}\\x1b[${reservedRows - 1}B`;\n\t\t\t\tindex += reservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbuffer += line;\n\t\t}\n\t\tbuffer += \"\\x1b[?2026l\";\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = Math.max(0, frame.newLines.length - 1);\n\t\tthis.hardwareCursorRow = this.cursorRow;\n\t\tthis.maxLinesRendered = clear ? frame.newLines.length : Math.max(this.maxLinesRendered, frame.newLines.length);\n\t\tconst bufferLength = Math.max(frame.height, frame.newLines.length);\n\t\tthis.previousViewportTop = Math.max(0, bufferLength - frame.height);\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.previousLines = frame.newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(frame.newLines);\n\t\tthis.previousWidth = frame.width;\n\t\tthis.previousHeight = frame.height;\n\t}\n\n\tprivate renderRequiredFullFrame(frame: MainScreenRenderFrame): boolean {\n\t\tif (this.previousLines.length === 0 && !frame.widthChanged && !frame.heightChanged) {\n\t\t\tthis.logFullRedraw(frame, \"first render\");\n\t\t\tthis.renderFullFrame(frame, false);\n\t\t\treturn true;\n\t\t}\n\t\tif (frame.widthChanged) {\n\t\t\tthis.logFullRedraw(frame, `terminal width changed (${this.previousWidth} -> ${frame.width})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\tif (frame.heightChanged && !isTermuxSession()) {\n\t\t\tthis.logFullRedraw(frame, `terminal height changed (${this.previousHeight} -> ${frame.height})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\tif (this.getClearOnShrink() && frame.newLines.length < this.maxLinesRendered && !this.hasOverlayEntries) {\n\t\t\tthis.logFullRedraw(frame, `clearOnShrink (maxLinesRendered=${this.maxLinesRendered})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate findChangedContent(frame: MainScreenRenderFrame): ChangedContentRange | undefined {\n\t\tlet firstChanged = -1;\n\t\tlet lastChanged = -1;\n\t\tconst maxLines = Math.max(frame.newLines.length, this.previousLines.length);\n\t\tfor (let index = 0; index < maxLines; index++) {\n\t\t\tconst oldLine = index < this.previousLines.length ? this.previousLines[index] : \"\";\n\t\t\tconst newLine = index < frame.newLines.length ? frame.newLines[index] : \"\";\n\t\t\tif (oldLine === newLine) continue;\n\t\t\tif (firstChanged === -1) firstChanged = index;\n\t\t\tlastChanged = index;\n\t\t}\n\n\t\tconst appendedLines = frame.newLines.length > this.previousLines.length;\n\t\tif (appendedLines) {\n\t\t\tif (firstChanged === -1) firstChanged = this.previousLines.length;\n\t\t\tlastChanged = frame.newLines.length - 1;\n\t\t}\n\t\tif (firstChanged === -1) return undefined;\n\n\t\tconst expanded = this.expandChangedRangeForKittyImages(firstChanged, lastChanged, frame.newLines);\n\t\treturn {\n\t\t\t...expanded,\n\t\t\tappendStart: appendedLines && expanded.firstChanged === this.previousLines.length && expanded.firstChanged > 0,\n\t\t};\n\t}\n\n\tprivate commitFrameHistory(frame: MainScreenRenderFrame, viewportTop: number): void {\n\t\tthis.previousLines = frame.newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(frame.newLines);\n\t\tthis.previousWidth = frame.width;\n\t\tthis.previousHeight = frame.height;\n\t\tthis.previousViewportTop = viewportTop;\n\t}\n\n\tprivate handleUnchangedFrame(frame: MainScreenRenderFrame): void {\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.previousViewportTop = frame.previousViewportTop;\n\t\tthis.previousHeight = frame.height;\n\t}\n\n\tprivate renderDeletedContent(frame: MainScreenRenderFrame, range: ChangedContentRange): void {\n\t\tif (this.previousLines.length <= frame.newLines.length) {\n\t\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\t\tthis.commitFrameHistory(frame, frame.previousViewportTop);\n\t\t\treturn;\n\t\t}\n\n\t\tlet buffer = \"\\x1b[?2026h\";\n\t\tbuffer += this.deleteChangedKittyImages(range.firstChanged, range.lastChanged);\n\t\tconst targetRow = Math.max(0, frame.newLines.length - 1);\n\t\tif (targetRow < frame.previousViewportTop) {\n\t\t\tthis.logFullRedraw(frame, `deleted lines moved viewport up (${targetRow} < ${frame.previousViewportTop})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\t\tconst lineDiff = this.getLineDiff(\n\t\t\ttargetRow,\n\t\t\tthis.hardwareCursorRow,\n\t\t\tframe.previousViewportTop,\n\t\t\tframe.previousViewportTop,\n\t\t);\n\t\tif (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n\t\telse if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n\t\tbuffer += \"\\r\";\n\t\tconst extraLines = this.previousLines.length - frame.newLines.length;\n\t\tif (extraLines > frame.height) {\n\t\t\tthis.logFullRedraw(frame, `extraLines > height (${extraLines} > ${frame.height})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\t\tconst clearStartOffset = frame.newLines.length === 0 ? 0 : 1;\n\t\tif (extraLines > 0 && clearStartOffset > 0) buffer += `\\x1b[${clearStartOffset}B`;\n\t\tfor (let index = 0; index < extraLines; index++) {\n\t\t\tbuffer += \"\\r\\x1b[2K\";\n\t\t\tif (index < extraLines - 1) buffer += \"\\x1b[1B\";\n\t\t}\n\t\tconst moveBack = Math.max(0, extraLines - 1 + clearStartOffset);\n\t\tif (moveBack > 0) buffer += `\\x1b[${moveBack}A`;\n\t\tbuffer += \"\\x1b[?2026l\";\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = targetRow;\n\t\tthis.hardwareCursorRow = targetRow;\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.commitFrameHistory(frame, frame.previousViewportTop);\n\t}\n\n\tprivate assertRenderedLineFits(line: string, index: number, frame: MainScreenRenderFrame): void {\n\t\tif (isImageLine(line) || visibleWidth(line) <= frame.width) return;\n\t\tconst crashLogPath = path.join(this.logDirectory, \"grip-crash.log\");\n\t\tconst crashData = [\n\t\t\t`Crash at ${new Date().toISOString()}`,\n\t\t\t`Terminal width: ${frame.width}`,\n\t\t\t`Line ${index} visible width: ${visibleWidth(line)}`,\n\t\t\t\"\",\n\t\t\t\"=== All rendered lines ===\",\n\t\t\t...frame.newLines.map(\n\t\t\t\t(renderedLine, lineIndex) => `[${lineIndex}] (w=${visibleWidth(renderedLine)}) ${renderedLine}`,\n\t\t\t),\n\t\t\t\"\",\n\t\t].join(\"\\n\");\n\t\tfs.mkdirSync(path.dirname(crashLogPath), { recursive: true });\n\t\tfs.writeFileSync(crashLogPath, crashData);\n\t\tthis.stop();\n\t\tthrow new Error(\n\t\t\t[\n\t\t\t\t`Rendered line ${index} exceeds terminal width (${visibleWidth(line)} > ${frame.width}).`,\n\t\t\t\t\"\",\n\t\t\t\t\"This is likely caused by a custom TUI component not truncating its output.\",\n\t\t\t\t\"Use visibleWidth() to measure and truncateToWidth() to truncate lines.\",\n\t\t\t\t\"\",\n\t\t\t\t`Debug log written to: ${crashLogPath}`,\n\t\t\t].join(\"\\n\"),\n\t\t);\n\t}\n\n\tprivate renderChangedLines(\n\t\tframe: MainScreenRenderFrame,\n\t\trange: ChangedContentRange,\n\t\tviewportTop: number,\n\t\tinitialBuffer: string,\n\t): ChangedLinesRenderResult | undefined {\n\t\tlet buffer = initialBuffer;\n\t\tconst renderEnd = Math.min(range.lastChanged, frame.newLines.length - 1);\n\t\tfor (let index = range.firstChanged; index <= renderEnd; index++) {\n\t\t\tif (index > range.firstChanged) buffer += \"\\r\\n\";\n\t\t\tconst line = frame.newLines[index];\n\t\t\tconst reservedRows = isImageLine(line) ? this.getKittyImageReservedRows(frame.newLines, index, renderEnd) : 1;\n\t\t\tif (reservedRows > 1) {\n\t\t\t\tconst imageStartScreenRow = index - viewportTop;\n\t\t\t\tif (imageStartScreenRow < 0 || imageStartScreenRow + reservedRows > frame.height) {\n\t\t\t\t\tthis.logFullRedraw(\n\t\t\t\t\t\tframe,\n\t\t\t\t\t\t`kitty image pre-clear would scroll (${imageStartScreenRow} + ${reservedRows} > ${frame.height})`,\n\t\t\t\t\t);\n\t\t\t\t\tthis.renderFullFrame(frame, true);\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tbuffer += \"\\x1b[2K\";\n\t\t\t\tfor (let row = 1; row < reservedRows; row++) buffer += \"\\r\\n\\x1b[2K\";\n\t\t\t\tbuffer += `\\x1b[${reservedRows - 1}A${line}\\x1b[${reservedRows - 1}B`;\n\t\t\t\tindex += reservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbuffer += \"\\x1b[2K\";\n\t\t\tthis.assertRenderedLineFits(line, index, frame);\n\t\t\tbuffer += line;\n\t\t}\n\t\treturn { buffer, renderEnd };\n\t}\n\n\tprivate writeDifferentialDebugLog(\n\t\tframe: MainScreenRenderFrame,\n\t\trange: ChangedContentRange,\n\t\tviewportTop: number,\n\t\thardwareCursorRow: number,\n\t\tlineDiff: number,\n\t\trenderEnd: number,\n\t\tfinalCursorRow: number,\n\t\tbuffer: string,\n\t): void {\n\t\tif (process.env.GRIP_TUI_DEBUG !== \"1\") return;\n\t\tconst debugDir = \"/tmp/tui\";\n\t\tfs.mkdirSync(debugDir, { recursive: true });\n\t\tconst debugPath = path.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);\n\t\tconst debugData = [\n\t\t\t`firstChanged: ${range.firstChanged}`,\n\t\t\t`viewportTop: ${viewportTop}`,\n\t\t\t`cursorRow: ${this.cursorRow}`,\n\t\t\t`height: ${frame.height}`,\n\t\t\t`lineDiff: ${lineDiff}`,\n\t\t\t`hardwareCursorRow: ${hardwareCursorRow}`,\n\t\t\t`renderEnd: ${renderEnd}`,\n\t\t\t`finalCursorRow: ${finalCursorRow}`,\n\t\t\t`cursorPos: ${JSON.stringify(frame.cursorPosition)}`,\n\t\t\t`newLines.length: ${frame.newLines.length}`,\n\t\t\t`previousLines.length: ${this.previousLines.length}`,\n\t\t\t\"\",\n\t\t\t\"=== newLines ===\",\n\t\t\tJSON.stringify(frame.newLines, null, 2),\n\t\t\t\"\",\n\t\t\t\"=== previousLines ===\",\n\t\t\tJSON.stringify(this.previousLines, null, 2),\n\t\t\t\"\",\n\t\t\t\"=== buffer ===\",\n\t\t\tJSON.stringify(buffer),\n\t\t].join(\"\\n\");\n\t\tfs.writeFileSync(debugPath, debugData);\n\t}\n\n\tprivate renderDifferentialContent(frame: MainScreenRenderFrame, range: ChangedContentRange): void {\n\t\tif (range.firstChanged < frame.previousViewportTop) {\n\t\t\tthis.logFullRedraw(frame, `firstChanged < viewportTop (${range.firstChanged} < ${frame.previousViewportTop})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\n\t\tlet previousViewportTop = frame.previousViewportTop;\n\t\tlet viewportTop = previousViewportTop;\n\t\tlet hardwareCursorRow = this.hardwareCursorRow;\n\t\tlet buffer = `\\x1b[?2026h${this.deleteChangedKittyImages(range.firstChanged, range.lastChanged)}`;\n\t\tconst previousViewportBottom = previousViewportTop + frame.height - 1;\n\t\tconst moveTargetRow = range.appendStart ? range.firstChanged - 1 : range.firstChanged;\n\t\tif (moveTargetRow > previousViewportBottom) {\n\t\t\tconst currentScreenRow = Math.max(0, Math.min(frame.height - 1, hardwareCursorRow - previousViewportTop));\n\t\t\tconst moveToBottom = frame.height - 1 - currentScreenRow;\n\t\t\tif (moveToBottom > 0) buffer += `\\x1b[${moveToBottom}B`;\n\t\t\tconst scroll = moveTargetRow - previousViewportBottom;\n\t\t\tbuffer += \"\\r\\n\".repeat(scroll);\n\t\t\tpreviousViewportTop += scroll;\n\t\t\tviewportTop += scroll;\n\t\t\thardwareCursorRow = moveTargetRow;\n\t\t}\n\n\t\tconst lineDiff = this.getLineDiff(moveTargetRow, hardwareCursorRow, previousViewportTop, viewportTop);\n\t\tif (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n\t\telse if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n\t\tbuffer += range.appendStart ? \"\\r\\n\" : \"\\r\";\n\n\t\tconst changedLines = this.renderChangedLines(frame, range, viewportTop, buffer);\n\t\tif (!changedLines) return;\n\t\tbuffer = changedLines.buffer;\n\t\tlet finalCursorRow = changedLines.renderEnd;\n\t\tif (this.previousLines.length > frame.newLines.length) {\n\t\t\tif (changedLines.renderEnd < frame.newLines.length - 1) {\n\t\t\t\tconst moveDown = frame.newLines.length - 1 - changedLines.renderEnd;\n\t\t\t\tbuffer += `\\x1b[${moveDown}B`;\n\t\t\t\tfinalCursorRow = frame.newLines.length - 1;\n\t\t\t}\n\t\t\tconst extraLines = this.previousLines.length - frame.newLines.length;\n\t\t\tfor (let index = frame.newLines.length; index < this.previousLines.length; index++) {\n\t\t\t\tbuffer += \"\\r\\n\\x1b[2K\";\n\t\t\t}\n\t\t\tbuffer += `\\x1b[${extraLines}A`;\n\t\t}\n\t\tbuffer += \"\\x1b[?2026l\";\n\n\t\tthis.writeDifferentialDebugLog(\n\t\t\tframe,\n\t\t\trange,\n\t\t\tviewportTop,\n\t\t\thardwareCursorRow,\n\t\t\tlineDiff,\n\t\t\tchangedLines.renderEnd,\n\t\t\tfinalCursorRow,\n\t\t\tbuffer,\n\t\t);\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = Math.max(0, frame.newLines.length - 1);\n\t\tthis.hardwareCursorRow = finalCursorRow;\n\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, frame.newLines.length);\n\t\tconst committedViewportTop = Math.max(previousViewportTop, finalCursorRow - frame.height + 1);\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.commitFrameHistory(frame, committedViewportTop);\n\t}\n\n\tprotected doRender(): void {\n\t\tif (this.stopped) return;\n\t\tconst frame = this.prepareRenderFrame();\n\t\tif (this.renderRequiredFullFrame(frame)) return;\n\t\tconst changedContent = this.findChangedContent(frame);\n\t\tif (!changedContent) {\n\t\t\tthis.handleUnchangedFrame(frame);\n\t\t\treturn;\n\t\t}\n\t\tif (changedContent.firstChanged >= frame.newLines.length) {\n\t\t\tthis.renderDeletedContent(frame, changedContent);\n\t\t\treturn;\n\t\t}\n\t\tthis.renderDifferentialContent(frame, changedContent);\n\t}\n\n\t/**\n\t * Position the hardware cursor for IME candidate window.\n\t * @param cursorPos The cursor position extracted from rendered output, or null\n\t * @param totalLines Total number of rendered lines\n\t */\n\tprivate positionHardwareCursor(cursorPos: RenderedCursorPosition | null, totalLines: number): void {\n\t\tif (!cursorPos || totalLines <= 0) {\n\t\t\tthis.terminal.hideCursor();\n\t\t\treturn;\n\t\t}\n\n\t\t// Clamp cursor position to valid range\n\t\tconst targetRow = Math.max(0, Math.min(cursorPos.row, totalLines - 1));\n\t\tconst targetCol = Math.max(0, cursorPos.col);\n\n\t\t// Move cursor from current position to target\n\t\tconst rowDelta = targetRow - this.hardwareCursorRow;\n\t\tlet buffer = \"\";\n\t\tif (rowDelta > 0) {\n\t\t\tbuffer += `\\x1b[${rowDelta}B`; // Move down\n\t\t} else if (rowDelta < 0) {\n\t\t\tbuffer += `\\x1b[${-rowDelta}A`; // Move up\n\t\t}\n\t\t// Move to absolute column (1-indexed)\n\t\tbuffer += `\\x1b[${targetCol + 1}G`;\n\n\t\tif (buffer) {\n\t\t\tthis.terminal.write(buffer);\n\t\t}\n\n\t\tthis.hardwareCursorRow = targetRow;\n\t\tif (this.getShowHardwareCursor()) {\n\t\t\tthis.terminal.showCursor();\n\t\t} else {\n\t\t\tthis.terminal.hideCursor();\n\t\t}\n\t}\n}\n"]}
@@ -4,6 +4,7 @@ import { deleteKittyImage, isImageLine } from "./terminal-image.js";
4
4
  import { TuiBase } from "./tui.js";
5
5
  import { visibleWidth } from "./utils.js";
6
6
  const KITTY_SEQUENCE_PREFIX = "\x1b_G";
7
+ const OSC133_ZONE_PREFIX = /^(?:\x1b\]133;[ABC](?:\x07|\x1b\\))+/;
7
8
  function parseKittyImageHeader(line) {
8
9
  const sequenceStart = line.indexOf(KITTY_SEQUENCE_PREFIX);
9
10
  if (sequenceStart === -1)
@@ -161,7 +162,9 @@ export class TuiMainScreen extends TuiBase {
161
162
  if (this.hasOverlayEntries)
162
163
  newLines = this.compositeOverlays(newLines, width, height);
163
164
  const cursorPosition = this.extractCursorPosition(newLines, height);
164
- newLines = this.applyLineResets(newLines);
165
+ // Preserve component zone markers for alt-screen navigation, but do not emit
166
+ // them here: terminals draw their own gutter indicators for OSC 133.
167
+ newLines = this.applyLineResets(newLines.map((line) => line.replace(OSC133_ZONE_PREFIX, "")));
165
168
  return { width, height, widthChanged, heightChanged, newLines, cursorPosition, previousViewportTop };
166
169
  }
167
170
  getLineDiff(targetRow, hardwareCursorRow, previousViewportTop, viewportTop) {
@@ -1 +1 @@
1
- {"version":3,"file":"tui-main-screen.js","sourceRoot":"","sources":["../src/tui-main-screen.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { deleteKittyImage, isImageLine } from \"./terminal-image.ts\";\nimport { type RenderedCursorPosition, type TUI, TuiBase, type TuiStopOptions } from \"./tui.ts\";\nimport { visibleWidth } from \"./utils.ts\";\n\nconst KITTY_SEQUENCE_PREFIX = \"\\x1b_G\";\n\ninterface KittyImageHeader {\n\tids: number[];\n\trows: number;\n}\n\ninterface ChangedLineRange {\n\tfirstChanged: number;\n\tlastChanged: number;\n}\n\ninterface ChangedContentRange extends ChangedLineRange {\n\tappendStart: boolean;\n}\n\ninterface MainScreenRenderFrame {\n\twidth: number;\n\theight: number;\n\twidthChanged: boolean;\n\theightChanged: boolean;\n\tnewLines: string[];\n\tcursorPosition: RenderedCursorPosition | null;\n\tpreviousViewportTop: number;\n}\n\ninterface ChangedLinesRenderResult {\n\tbuffer: string;\n\trenderEnd: number;\n}\n\nfunction parseKittyImageHeader(line: string): KittyImageHeader | undefined {\n\tconst sequenceStart = line.indexOf(KITTY_SEQUENCE_PREFIX);\n\tif (sequenceStart === -1) return undefined;\n\tconst paramsStart = sequenceStart + KITTY_SEQUENCE_PREFIX.length;\n\tconst paramsEnd = line.indexOf(\";\", paramsStart);\n\tif (paramsEnd === -1) return undefined;\n\n\tconst ids: number[] = [];\n\tlet rows = 1;\n\tfor (const param of line.slice(paramsStart, paramsEnd).split(\",\")) {\n\t\tconst [key, value] = param.split(\"=\", 2);\n\t\tif (value === undefined) continue;\n\t\tconst numberValue = Number(value);\n\t\tif (!Number.isInteger(numberValue) || numberValue <= 0 || numberValue > 0xffffffff) continue;\n\t\tif (key === \"i\") ids.push(numberValue);\n\t\telse if (key === \"r\") rows = numberValue;\n\t}\n\treturn { ids, rows };\n}\n\nfunction extractKittyImageIds(line: string): number[] {\n\treturn parseKittyImageHeader(line)?.ids ?? [];\n}\n\nfunction extractKittyImageRows(line: string): number {\n\treturn parseKittyImageHeader(line)?.rows ?? 1;\n}\n\nfunction isTermuxSession(): boolean {\n\treturn Boolean(process.env.TERMUX_VERSION);\n}\n\nexport interface TuiMainScreenRenderState {\n\tpreviousLines: string[];\n\tpreviousWidth: number;\n\tpreviousHeight: number;\n\tcursorRow: number;\n\thardwareCursorRow: number;\n\tmaxLinesRendered: number;\n\tpreviousViewportTop: number;\n}\n\n/** TUI implementation that renders into the terminal's main screen and scrollback. */\nexport class TuiMainScreen extends TuiBase implements TUI {\n\treadonly mode = \"regular\" as const;\n\tprivate previousLines: string[] = [];\n\tprivate previousKittyImageIds = new Set<number>();\n\tprivate previousWidth = 0;\n\tprivate previousHeight = 0;\n\tprivate cursorRow = 0;\n\tprivate hardwareCursorRow = 0;\n\tprivate maxLinesRendered = 0;\n\tprivate previousViewportTop = 0;\n\n\tcaptureRenderState(): TuiMainScreenRenderState {\n\t\treturn {\n\t\t\tpreviousLines: [...this.previousLines],\n\t\t\tpreviousWidth: this.previousWidth,\n\t\t\tpreviousHeight: this.previousHeight,\n\t\t\tcursorRow: this.cursorRow,\n\t\t\thardwareCursorRow: this.hardwareCursorRow,\n\t\t\tmaxLinesRendered: this.maxLinesRendered,\n\t\t\tpreviousViewportTop: this.previousViewportTop,\n\t\t};\n\t}\n\n\trestoreRenderState(state: TuiMainScreenRenderState): void {\n\t\tthis.previousLines = state.previousLines.map((line) => (isImageLine(line) ? \"\" : line));\n\t\tthis.previousKittyImageIds = new Set();\n\t\tthis.previousWidth = state.previousWidth;\n\t\tthis.previousHeight = state.previousHeight;\n\t\tthis.cursorRow = state.cursorRow;\n\t\tthis.hardwareCursorRow = state.hardwareCursorRow;\n\t\tthis.maxLinesRendered = state.maxLinesRendered;\n\t\tthis.previousViewportTop = state.previousViewportTop;\n\t}\n\n\tprotected override resetRenderState(): void {\n\t\tthis.previousLines = [];\n\t\tthis.previousWidth = -1;\n\t\tthis.previousHeight = -1;\n\t\tthis.cursorRow = 0;\n\t\tthis.hardwareCursorRow = 0;\n\t\tthis.maxLinesRendered = 0;\n\t\tthis.previousViewportTop = 0;\n\t}\n\n\tprotected override beforeTerminalStop(options?: TuiStopOptions): void {\n\t\tif (options?.preserveScreen || this.previousLines.length === 0) return;\n\t\tthis.terminal.write(\" \");\n\t\tconst targetRow = this.previousLines.length;\n\t\tconst lineDiff = targetRow - this.hardwareCursorRow;\n\t\tif (lineDiff > 0) this.terminal.write(`\\x1b[${lineDiff}B`);\n\t\telse if (lineDiff < 0) this.terminal.write(`\\x1b[${-lineDiff}A`);\n\t\tthis.terminal.write(\"\\r\\n\");\n\t}\n\n\tprivate collectKittyImageIds(lines: string[]): Set<number> {\n\t\tconst ids = new Set<number>();\n\t\tfor (const line of lines) {\n\t\t\tfor (const id of extractKittyImageIds(line)) {\n\t\t\t\tids.add(id);\n\t\t\t}\n\t\t}\n\t\treturn ids;\n\t}\n\n\tprivate deleteKittyImages(ids: Iterable<number>): string {\n\t\tlet buffer = \"\";\n\t\tfor (const id of ids) {\n\t\t\tbuffer += deleteKittyImage(id);\n\t\t}\n\t\treturn buffer;\n\t}\n\n\tprivate getKittyImageReservedRows(lines: string[], index: number, maxIndex = lines.length - 1): number {\n\t\tconst rows = extractKittyImageRows(lines[index] ?? \"\");\n\t\tif (rows <= 1) return 1;\n\n\t\tconst maxRows = Math.min(rows, maxIndex - index + 1, lines.length - index);\n\t\tlet reservedRows = 1;\n\t\twhile (reservedRows < maxRows) {\n\t\t\tconst line = lines[index + reservedRows] ?? \"\";\n\t\t\tif (isImageLine(line) || visibleWidth(line) > 0) break;\n\t\t\treservedRows++;\n\t\t}\n\t\treturn reservedRows;\n\t}\n\n\tprivate expandChangedRangeForKittyImages(\n\t\tfirstChanged: number,\n\t\tlastChanged: number,\n\t\tnewLines: string[],\n\t): ChangedLineRange {\n\t\tlet expandedFirstChanged = firstChanged;\n\t\tlet expandedLastChanged = lastChanged;\n\t\tconst expandForLines = (lines: string[]): void => {\n\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\tif (extractKittyImageIds(lines[i]).length === 0) continue;\n\t\t\t\tconst blockEnd = i + this.getKittyImageReservedRows(lines, i) - 1;\n\t\t\t\tif (i >= firstChanged || (i <= lastChanged && blockEnd >= firstChanged)) {\n\t\t\t\t\texpandedFirstChanged = Math.min(expandedFirstChanged, i);\n\t\t\t\t\texpandedLastChanged = Math.max(expandedLastChanged, blockEnd);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\texpandForLines(this.previousLines);\n\t\texpandForLines(newLines);\n\t\treturn { firstChanged: expandedFirstChanged, lastChanged: expandedLastChanged };\n\t}\n\n\tprivate deleteChangedKittyImages(firstChanged: number, lastChanged: number): string {\n\t\tif (firstChanged < 0 || lastChanged < firstChanged) return \"\";\n\n\t\tconst ids = new Set<number>();\n\t\tconst maxLine = Math.min(lastChanged, this.previousLines.length - 1);\n\t\tfor (let i = firstChanged; i <= maxLine; i++) {\n\t\t\tfor (const id of extractKittyImageIds(this.previousLines[i] ?? \"\")) {\n\t\t\t\tids.add(id);\n\t\t\t}\n\t\t}\n\n\t\treturn this.deleteKittyImages(ids);\n\t}\n\n\tprivate prepareRenderFrame(): MainScreenRenderFrame {\n\t\tconst width = this.terminal.columns;\n\t\tconst height = this.terminal.rows;\n\t\tconst widthChanged = this.previousWidth !== 0 && this.previousWidth !== width;\n\t\tconst heightChanged = this.previousHeight !== 0 && this.previousHeight !== height;\n\t\tconst previousBufferLength = this.previousHeight > 0 ? this.previousViewportTop + this.previousHeight : height;\n\t\tconst previousViewportTop = heightChanged ? Math.max(0, previousBufferLength - height) : this.previousViewportTop;\n\n\t\tlet newLines = this.render(width);\n\t\tif (this.hasOverlayEntries) newLines = this.compositeOverlays(newLines, width, height);\n\t\tconst cursorPosition = this.extractCursorPosition(newLines, height);\n\t\tnewLines = this.applyLineResets(newLines);\n\t\treturn { width, height, widthChanged, heightChanged, newLines, cursorPosition, previousViewportTop };\n\t}\n\n\tprivate getLineDiff(\n\t\ttargetRow: number,\n\t\thardwareCursorRow: number,\n\t\tpreviousViewportTop: number,\n\t\tviewportTop: number,\n\t): number {\n\t\tconst currentScreenRow = hardwareCursorRow - previousViewportTop;\n\t\tconst targetScreenRow = targetRow - viewportTop;\n\t\treturn targetScreenRow - currentScreenRow;\n\t}\n\n\tprivate logFullRedraw(frame: MainScreenRenderFrame, reason: string): void {\n\t\tif (process.env.GRIP_DEBUG_REDRAW !== \"1\") return;\n\t\tconst logPath = path.join(this.logDirectory, \"grip-debug.log\");\n\t\tconst message = `[${new Date().toISOString()}] fullRender: ${reason} (prev=${this.previousLines.length}, new=${frame.newLines.length}, height=${frame.height})\\n`;\n\t\tfs.mkdirSync(path.dirname(logPath), { recursive: true });\n\t\tfs.appendFileSync(logPath, message);\n\t}\n\n\tprivate renderFullFrame(frame: MainScreenRenderFrame, clear: boolean): void {\n\t\tthis.fullRedrawCount += 1;\n\t\tlet buffer = \"\\x1b[?2026h\";\n\t\tif (clear) {\n\t\t\tbuffer += this.deleteKittyImages(this.previousKittyImageIds);\n\t\t\tbuffer += \"\\x1b[2J\\x1b[H\\x1b[3J\";\n\t\t}\n\t\tfor (let index = 0; index < frame.newLines.length; index++) {\n\t\t\tif (index > 0) buffer += \"\\r\\n\";\n\t\t\tconst line = frame.newLines[index];\n\t\t\tconst reservedRows = isImageLine(line) ? this.getKittyImageReservedRows(frame.newLines, index) : 1;\n\t\t\tif (reservedRows > 1 && reservedRows <= frame.height) {\n\t\t\t\tbuffer += \"\\r\\n\".repeat(reservedRows - 1);\n\t\t\t\tbuffer += `\\x1b[${reservedRows - 1}A${line}\\x1b[${reservedRows - 1}B`;\n\t\t\t\tindex += reservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbuffer += line;\n\t\t}\n\t\tbuffer += \"\\x1b[?2026l\";\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = Math.max(0, frame.newLines.length - 1);\n\t\tthis.hardwareCursorRow = this.cursorRow;\n\t\tthis.maxLinesRendered = clear ? frame.newLines.length : Math.max(this.maxLinesRendered, frame.newLines.length);\n\t\tconst bufferLength = Math.max(frame.height, frame.newLines.length);\n\t\tthis.previousViewportTop = Math.max(0, bufferLength - frame.height);\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.previousLines = frame.newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(frame.newLines);\n\t\tthis.previousWidth = frame.width;\n\t\tthis.previousHeight = frame.height;\n\t}\n\n\tprivate renderRequiredFullFrame(frame: MainScreenRenderFrame): boolean {\n\t\tif (this.previousLines.length === 0 && !frame.widthChanged && !frame.heightChanged) {\n\t\t\tthis.logFullRedraw(frame, \"first render\");\n\t\t\tthis.renderFullFrame(frame, false);\n\t\t\treturn true;\n\t\t}\n\t\tif (frame.widthChanged) {\n\t\t\tthis.logFullRedraw(frame, `terminal width changed (${this.previousWidth} -> ${frame.width})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\tif (frame.heightChanged && !isTermuxSession()) {\n\t\t\tthis.logFullRedraw(frame, `terminal height changed (${this.previousHeight} -> ${frame.height})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\tif (this.getClearOnShrink() && frame.newLines.length < this.maxLinesRendered && !this.hasOverlayEntries) {\n\t\t\tthis.logFullRedraw(frame, `clearOnShrink (maxLinesRendered=${this.maxLinesRendered})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate findChangedContent(frame: MainScreenRenderFrame): ChangedContentRange | undefined {\n\t\tlet firstChanged = -1;\n\t\tlet lastChanged = -1;\n\t\tconst maxLines = Math.max(frame.newLines.length, this.previousLines.length);\n\t\tfor (let index = 0; index < maxLines; index++) {\n\t\t\tconst oldLine = index < this.previousLines.length ? this.previousLines[index] : \"\";\n\t\t\tconst newLine = index < frame.newLines.length ? frame.newLines[index] : \"\";\n\t\t\tif (oldLine === newLine) continue;\n\t\t\tif (firstChanged === -1) firstChanged = index;\n\t\t\tlastChanged = index;\n\t\t}\n\n\t\tconst appendedLines = frame.newLines.length > this.previousLines.length;\n\t\tif (appendedLines) {\n\t\t\tif (firstChanged === -1) firstChanged = this.previousLines.length;\n\t\t\tlastChanged = frame.newLines.length - 1;\n\t\t}\n\t\tif (firstChanged === -1) return undefined;\n\n\t\tconst expanded = this.expandChangedRangeForKittyImages(firstChanged, lastChanged, frame.newLines);\n\t\treturn {\n\t\t\t...expanded,\n\t\t\tappendStart: appendedLines && expanded.firstChanged === this.previousLines.length && expanded.firstChanged > 0,\n\t\t};\n\t}\n\n\tprivate commitFrameHistory(frame: MainScreenRenderFrame, viewportTop: number): void {\n\t\tthis.previousLines = frame.newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(frame.newLines);\n\t\tthis.previousWidth = frame.width;\n\t\tthis.previousHeight = frame.height;\n\t\tthis.previousViewportTop = viewportTop;\n\t}\n\n\tprivate handleUnchangedFrame(frame: MainScreenRenderFrame): void {\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.previousViewportTop = frame.previousViewportTop;\n\t\tthis.previousHeight = frame.height;\n\t}\n\n\tprivate renderDeletedContent(frame: MainScreenRenderFrame, range: ChangedContentRange): void {\n\t\tif (this.previousLines.length <= frame.newLines.length) {\n\t\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\t\tthis.commitFrameHistory(frame, frame.previousViewportTop);\n\t\t\treturn;\n\t\t}\n\n\t\tlet buffer = \"\\x1b[?2026h\";\n\t\tbuffer += this.deleteChangedKittyImages(range.firstChanged, range.lastChanged);\n\t\tconst targetRow = Math.max(0, frame.newLines.length - 1);\n\t\tif (targetRow < frame.previousViewportTop) {\n\t\t\tthis.logFullRedraw(frame, `deleted lines moved viewport up (${targetRow} < ${frame.previousViewportTop})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\t\tconst lineDiff = this.getLineDiff(\n\t\t\ttargetRow,\n\t\t\tthis.hardwareCursorRow,\n\t\t\tframe.previousViewportTop,\n\t\t\tframe.previousViewportTop,\n\t\t);\n\t\tif (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n\t\telse if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n\t\tbuffer += \"\\r\";\n\t\tconst extraLines = this.previousLines.length - frame.newLines.length;\n\t\tif (extraLines > frame.height) {\n\t\t\tthis.logFullRedraw(frame, `extraLines > height (${extraLines} > ${frame.height})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\t\tconst clearStartOffset = frame.newLines.length === 0 ? 0 : 1;\n\t\tif (extraLines > 0 && clearStartOffset > 0) buffer += `\\x1b[${clearStartOffset}B`;\n\t\tfor (let index = 0; index < extraLines; index++) {\n\t\t\tbuffer += \"\\r\\x1b[2K\";\n\t\t\tif (index < extraLines - 1) buffer += \"\\x1b[1B\";\n\t\t}\n\t\tconst moveBack = Math.max(0, extraLines - 1 + clearStartOffset);\n\t\tif (moveBack > 0) buffer += `\\x1b[${moveBack}A`;\n\t\tbuffer += \"\\x1b[?2026l\";\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = targetRow;\n\t\tthis.hardwareCursorRow = targetRow;\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.commitFrameHistory(frame, frame.previousViewportTop);\n\t}\n\n\tprivate assertRenderedLineFits(line: string, index: number, frame: MainScreenRenderFrame): void {\n\t\tif (isImageLine(line) || visibleWidth(line) <= frame.width) return;\n\t\tconst crashLogPath = path.join(this.logDirectory, \"grip-crash.log\");\n\t\tconst crashData = [\n\t\t\t`Crash at ${new Date().toISOString()}`,\n\t\t\t`Terminal width: ${frame.width}`,\n\t\t\t`Line ${index} visible width: ${visibleWidth(line)}`,\n\t\t\t\"\",\n\t\t\t\"=== All rendered lines ===\",\n\t\t\t...frame.newLines.map(\n\t\t\t\t(renderedLine, lineIndex) => `[${lineIndex}] (w=${visibleWidth(renderedLine)}) ${renderedLine}`,\n\t\t\t),\n\t\t\t\"\",\n\t\t].join(\"\\n\");\n\t\tfs.mkdirSync(path.dirname(crashLogPath), { recursive: true });\n\t\tfs.writeFileSync(crashLogPath, crashData);\n\t\tthis.stop();\n\t\tthrow new Error(\n\t\t\t[\n\t\t\t\t`Rendered line ${index} exceeds terminal width (${visibleWidth(line)} > ${frame.width}).`,\n\t\t\t\t\"\",\n\t\t\t\t\"This is likely caused by a custom TUI component not truncating its output.\",\n\t\t\t\t\"Use visibleWidth() to measure and truncateToWidth() to truncate lines.\",\n\t\t\t\t\"\",\n\t\t\t\t`Debug log written to: ${crashLogPath}`,\n\t\t\t].join(\"\\n\"),\n\t\t);\n\t}\n\n\tprivate renderChangedLines(\n\t\tframe: MainScreenRenderFrame,\n\t\trange: ChangedContentRange,\n\t\tviewportTop: number,\n\t\tinitialBuffer: string,\n\t): ChangedLinesRenderResult | undefined {\n\t\tlet buffer = initialBuffer;\n\t\tconst renderEnd = Math.min(range.lastChanged, frame.newLines.length - 1);\n\t\tfor (let index = range.firstChanged; index <= renderEnd; index++) {\n\t\t\tif (index > range.firstChanged) buffer += \"\\r\\n\";\n\t\t\tconst line = frame.newLines[index];\n\t\t\tconst reservedRows = isImageLine(line) ? this.getKittyImageReservedRows(frame.newLines, index, renderEnd) : 1;\n\t\t\tif (reservedRows > 1) {\n\t\t\t\tconst imageStartScreenRow = index - viewportTop;\n\t\t\t\tif (imageStartScreenRow < 0 || imageStartScreenRow + reservedRows > frame.height) {\n\t\t\t\t\tthis.logFullRedraw(\n\t\t\t\t\t\tframe,\n\t\t\t\t\t\t`kitty image pre-clear would scroll (${imageStartScreenRow} + ${reservedRows} > ${frame.height})`,\n\t\t\t\t\t);\n\t\t\t\t\tthis.renderFullFrame(frame, true);\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tbuffer += \"\\x1b[2K\";\n\t\t\t\tfor (let row = 1; row < reservedRows; row++) buffer += \"\\r\\n\\x1b[2K\";\n\t\t\t\tbuffer += `\\x1b[${reservedRows - 1}A${line}\\x1b[${reservedRows - 1}B`;\n\t\t\t\tindex += reservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbuffer += \"\\x1b[2K\";\n\t\t\tthis.assertRenderedLineFits(line, index, frame);\n\t\t\tbuffer += line;\n\t\t}\n\t\treturn { buffer, renderEnd };\n\t}\n\n\tprivate writeDifferentialDebugLog(\n\t\tframe: MainScreenRenderFrame,\n\t\trange: ChangedContentRange,\n\t\tviewportTop: number,\n\t\thardwareCursorRow: number,\n\t\tlineDiff: number,\n\t\trenderEnd: number,\n\t\tfinalCursorRow: number,\n\t\tbuffer: string,\n\t): void {\n\t\tif (process.env.GRIP_TUI_DEBUG !== \"1\") return;\n\t\tconst debugDir = \"/tmp/tui\";\n\t\tfs.mkdirSync(debugDir, { recursive: true });\n\t\tconst debugPath = path.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);\n\t\tconst debugData = [\n\t\t\t`firstChanged: ${range.firstChanged}`,\n\t\t\t`viewportTop: ${viewportTop}`,\n\t\t\t`cursorRow: ${this.cursorRow}`,\n\t\t\t`height: ${frame.height}`,\n\t\t\t`lineDiff: ${lineDiff}`,\n\t\t\t`hardwareCursorRow: ${hardwareCursorRow}`,\n\t\t\t`renderEnd: ${renderEnd}`,\n\t\t\t`finalCursorRow: ${finalCursorRow}`,\n\t\t\t`cursorPos: ${JSON.stringify(frame.cursorPosition)}`,\n\t\t\t`newLines.length: ${frame.newLines.length}`,\n\t\t\t`previousLines.length: ${this.previousLines.length}`,\n\t\t\t\"\",\n\t\t\t\"=== newLines ===\",\n\t\t\tJSON.stringify(frame.newLines, null, 2),\n\t\t\t\"\",\n\t\t\t\"=== previousLines ===\",\n\t\t\tJSON.stringify(this.previousLines, null, 2),\n\t\t\t\"\",\n\t\t\t\"=== buffer ===\",\n\t\t\tJSON.stringify(buffer),\n\t\t].join(\"\\n\");\n\t\tfs.writeFileSync(debugPath, debugData);\n\t}\n\n\tprivate renderDifferentialContent(frame: MainScreenRenderFrame, range: ChangedContentRange): void {\n\t\tif (range.firstChanged < frame.previousViewportTop) {\n\t\t\tthis.logFullRedraw(frame, `firstChanged < viewportTop (${range.firstChanged} < ${frame.previousViewportTop})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\n\t\tlet previousViewportTop = frame.previousViewportTop;\n\t\tlet viewportTop = previousViewportTop;\n\t\tlet hardwareCursorRow = this.hardwareCursorRow;\n\t\tlet buffer = `\\x1b[?2026h${this.deleteChangedKittyImages(range.firstChanged, range.lastChanged)}`;\n\t\tconst previousViewportBottom = previousViewportTop + frame.height - 1;\n\t\tconst moveTargetRow = range.appendStart ? range.firstChanged - 1 : range.firstChanged;\n\t\tif (moveTargetRow > previousViewportBottom) {\n\t\t\tconst currentScreenRow = Math.max(0, Math.min(frame.height - 1, hardwareCursorRow - previousViewportTop));\n\t\t\tconst moveToBottom = frame.height - 1 - currentScreenRow;\n\t\t\tif (moveToBottom > 0) buffer += `\\x1b[${moveToBottom}B`;\n\t\t\tconst scroll = moveTargetRow - previousViewportBottom;\n\t\t\tbuffer += \"\\r\\n\".repeat(scroll);\n\t\t\tpreviousViewportTop += scroll;\n\t\t\tviewportTop += scroll;\n\t\t\thardwareCursorRow = moveTargetRow;\n\t\t}\n\n\t\tconst lineDiff = this.getLineDiff(moveTargetRow, hardwareCursorRow, previousViewportTop, viewportTop);\n\t\tif (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n\t\telse if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n\t\tbuffer += range.appendStart ? \"\\r\\n\" : \"\\r\";\n\n\t\tconst changedLines = this.renderChangedLines(frame, range, viewportTop, buffer);\n\t\tif (!changedLines) return;\n\t\tbuffer = changedLines.buffer;\n\t\tlet finalCursorRow = changedLines.renderEnd;\n\t\tif (this.previousLines.length > frame.newLines.length) {\n\t\t\tif (changedLines.renderEnd < frame.newLines.length - 1) {\n\t\t\t\tconst moveDown = frame.newLines.length - 1 - changedLines.renderEnd;\n\t\t\t\tbuffer += `\\x1b[${moveDown}B`;\n\t\t\t\tfinalCursorRow = frame.newLines.length - 1;\n\t\t\t}\n\t\t\tconst extraLines = this.previousLines.length - frame.newLines.length;\n\t\t\tfor (let index = frame.newLines.length; index < this.previousLines.length; index++) {\n\t\t\t\tbuffer += \"\\r\\n\\x1b[2K\";\n\t\t\t}\n\t\t\tbuffer += `\\x1b[${extraLines}A`;\n\t\t}\n\t\tbuffer += \"\\x1b[?2026l\";\n\n\t\tthis.writeDifferentialDebugLog(\n\t\t\tframe,\n\t\t\trange,\n\t\t\tviewportTop,\n\t\t\thardwareCursorRow,\n\t\t\tlineDiff,\n\t\t\tchangedLines.renderEnd,\n\t\t\tfinalCursorRow,\n\t\t\tbuffer,\n\t\t);\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = Math.max(0, frame.newLines.length - 1);\n\t\tthis.hardwareCursorRow = finalCursorRow;\n\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, frame.newLines.length);\n\t\tconst committedViewportTop = Math.max(previousViewportTop, finalCursorRow - frame.height + 1);\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.commitFrameHistory(frame, committedViewportTop);\n\t}\n\n\tprotected doRender(): void {\n\t\tif (this.stopped) return;\n\t\tconst frame = this.prepareRenderFrame();\n\t\tif (this.renderRequiredFullFrame(frame)) return;\n\t\tconst changedContent = this.findChangedContent(frame);\n\t\tif (!changedContent) {\n\t\t\tthis.handleUnchangedFrame(frame);\n\t\t\treturn;\n\t\t}\n\t\tif (changedContent.firstChanged >= frame.newLines.length) {\n\t\t\tthis.renderDeletedContent(frame, changedContent);\n\t\t\treturn;\n\t\t}\n\t\tthis.renderDifferentialContent(frame, changedContent);\n\t}\n\n\t/**\n\t * Position the hardware cursor for IME candidate window.\n\t * @param cursorPos The cursor position extracted from rendered output, or null\n\t * @param totalLines Total number of rendered lines\n\t */\n\tprivate positionHardwareCursor(cursorPos: RenderedCursorPosition | null, totalLines: number): void {\n\t\tif (!cursorPos || totalLines <= 0) {\n\t\t\tthis.terminal.hideCursor();\n\t\t\treturn;\n\t\t}\n\n\t\t// Clamp cursor position to valid range\n\t\tconst targetRow = Math.max(0, Math.min(cursorPos.row, totalLines - 1));\n\t\tconst targetCol = Math.max(0, cursorPos.col);\n\n\t\t// Move cursor from current position to target\n\t\tconst rowDelta = targetRow - this.hardwareCursorRow;\n\t\tlet buffer = \"\";\n\t\tif (rowDelta > 0) {\n\t\t\tbuffer += `\\x1b[${rowDelta}B`; // Move down\n\t\t} else if (rowDelta < 0) {\n\t\t\tbuffer += `\\x1b[${-rowDelta}A`; // Move up\n\t\t}\n\t\t// Move to absolute column (1-indexed)\n\t\tbuffer += `\\x1b[${targetCol + 1}G`;\n\n\t\tif (buffer) {\n\t\t\tthis.terminal.write(buffer);\n\t\t}\n\n\t\tthis.hardwareCursorRow = targetRow;\n\t\tif (this.getShowHardwareCursor()) {\n\t\t\tthis.terminal.showCursor();\n\t\t} else {\n\t\t\tthis.terminal.hideCursor();\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"tui-main-screen.js","sourceRoot":"","sources":["../src/tui-main-screen.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { deleteKittyImage, isImageLine } from \"./terminal-image.ts\";\nimport { type RenderedCursorPosition, type TUI, TuiBase, type TuiStopOptions } from \"./tui.ts\";\nimport { visibleWidth } from \"./utils.ts\";\n\nconst KITTY_SEQUENCE_PREFIX = \"\\x1b_G\";\nconst OSC133_ZONE_PREFIX = /^(?:\\x1b\\]133;[ABC](?:\\x07|\\x1b\\\\))+/;\n\ninterface KittyImageHeader {\n\tids: number[];\n\trows: number;\n}\n\ninterface ChangedLineRange {\n\tfirstChanged: number;\n\tlastChanged: number;\n}\n\ninterface ChangedContentRange extends ChangedLineRange {\n\tappendStart: boolean;\n}\n\ninterface MainScreenRenderFrame {\n\twidth: number;\n\theight: number;\n\twidthChanged: boolean;\n\theightChanged: boolean;\n\tnewLines: string[];\n\tcursorPosition: RenderedCursorPosition | null;\n\tpreviousViewportTop: number;\n}\n\ninterface ChangedLinesRenderResult {\n\tbuffer: string;\n\trenderEnd: number;\n}\n\nfunction parseKittyImageHeader(line: string): KittyImageHeader | undefined {\n\tconst sequenceStart = line.indexOf(KITTY_SEQUENCE_PREFIX);\n\tif (sequenceStart === -1) return undefined;\n\tconst paramsStart = sequenceStart + KITTY_SEQUENCE_PREFIX.length;\n\tconst paramsEnd = line.indexOf(\";\", paramsStart);\n\tif (paramsEnd === -1) return undefined;\n\n\tconst ids: number[] = [];\n\tlet rows = 1;\n\tfor (const param of line.slice(paramsStart, paramsEnd).split(\",\")) {\n\t\tconst [key, value] = param.split(\"=\", 2);\n\t\tif (value === undefined) continue;\n\t\tconst numberValue = Number(value);\n\t\tif (!Number.isInteger(numberValue) || numberValue <= 0 || numberValue > 0xffffffff) continue;\n\t\tif (key === \"i\") ids.push(numberValue);\n\t\telse if (key === \"r\") rows = numberValue;\n\t}\n\treturn { ids, rows };\n}\n\nfunction extractKittyImageIds(line: string): number[] {\n\treturn parseKittyImageHeader(line)?.ids ?? [];\n}\n\nfunction extractKittyImageRows(line: string): number {\n\treturn parseKittyImageHeader(line)?.rows ?? 1;\n}\n\nfunction isTermuxSession(): boolean {\n\treturn Boolean(process.env.TERMUX_VERSION);\n}\n\nexport interface TuiMainScreenRenderState {\n\tpreviousLines: string[];\n\tpreviousWidth: number;\n\tpreviousHeight: number;\n\tcursorRow: number;\n\thardwareCursorRow: number;\n\tmaxLinesRendered: number;\n\tpreviousViewportTop: number;\n}\n\n/** TUI implementation that renders into the terminal's main screen and scrollback. */\nexport class TuiMainScreen extends TuiBase implements TUI {\n\treadonly mode = \"regular\" as const;\n\tprivate previousLines: string[] = [];\n\tprivate previousKittyImageIds = new Set<number>();\n\tprivate previousWidth = 0;\n\tprivate previousHeight = 0;\n\tprivate cursorRow = 0;\n\tprivate hardwareCursorRow = 0;\n\tprivate maxLinesRendered = 0;\n\tprivate previousViewportTop = 0;\n\n\tcaptureRenderState(): TuiMainScreenRenderState {\n\t\treturn {\n\t\t\tpreviousLines: [...this.previousLines],\n\t\t\tpreviousWidth: this.previousWidth,\n\t\t\tpreviousHeight: this.previousHeight,\n\t\t\tcursorRow: this.cursorRow,\n\t\t\thardwareCursorRow: this.hardwareCursorRow,\n\t\t\tmaxLinesRendered: this.maxLinesRendered,\n\t\t\tpreviousViewportTop: this.previousViewportTop,\n\t\t};\n\t}\n\n\trestoreRenderState(state: TuiMainScreenRenderState): void {\n\t\tthis.previousLines = state.previousLines.map((line) => (isImageLine(line) ? \"\" : line));\n\t\tthis.previousKittyImageIds = new Set();\n\t\tthis.previousWidth = state.previousWidth;\n\t\tthis.previousHeight = state.previousHeight;\n\t\tthis.cursorRow = state.cursorRow;\n\t\tthis.hardwareCursorRow = state.hardwareCursorRow;\n\t\tthis.maxLinesRendered = state.maxLinesRendered;\n\t\tthis.previousViewportTop = state.previousViewportTop;\n\t}\n\n\tprotected override resetRenderState(): void {\n\t\tthis.previousLines = [];\n\t\tthis.previousWidth = -1;\n\t\tthis.previousHeight = -1;\n\t\tthis.cursorRow = 0;\n\t\tthis.hardwareCursorRow = 0;\n\t\tthis.maxLinesRendered = 0;\n\t\tthis.previousViewportTop = 0;\n\t}\n\n\tprotected override beforeTerminalStop(options?: TuiStopOptions): void {\n\t\tif (options?.preserveScreen || this.previousLines.length === 0) return;\n\t\tthis.terminal.write(\" \");\n\t\tconst targetRow = this.previousLines.length;\n\t\tconst lineDiff = targetRow - this.hardwareCursorRow;\n\t\tif (lineDiff > 0) this.terminal.write(`\\x1b[${lineDiff}B`);\n\t\telse if (lineDiff < 0) this.terminal.write(`\\x1b[${-lineDiff}A`);\n\t\tthis.terminal.write(\"\\r\\n\");\n\t}\n\n\tprivate collectKittyImageIds(lines: string[]): Set<number> {\n\t\tconst ids = new Set<number>();\n\t\tfor (const line of lines) {\n\t\t\tfor (const id of extractKittyImageIds(line)) {\n\t\t\t\tids.add(id);\n\t\t\t}\n\t\t}\n\t\treturn ids;\n\t}\n\n\tprivate deleteKittyImages(ids: Iterable<number>): string {\n\t\tlet buffer = \"\";\n\t\tfor (const id of ids) {\n\t\t\tbuffer += deleteKittyImage(id);\n\t\t}\n\t\treturn buffer;\n\t}\n\n\tprivate getKittyImageReservedRows(lines: string[], index: number, maxIndex = lines.length - 1): number {\n\t\tconst rows = extractKittyImageRows(lines[index] ?? \"\");\n\t\tif (rows <= 1) return 1;\n\n\t\tconst maxRows = Math.min(rows, maxIndex - index + 1, lines.length - index);\n\t\tlet reservedRows = 1;\n\t\twhile (reservedRows < maxRows) {\n\t\t\tconst line = lines[index + reservedRows] ?? \"\";\n\t\t\tif (isImageLine(line) || visibleWidth(line) > 0) break;\n\t\t\treservedRows++;\n\t\t}\n\t\treturn reservedRows;\n\t}\n\n\tprivate expandChangedRangeForKittyImages(\n\t\tfirstChanged: number,\n\t\tlastChanged: number,\n\t\tnewLines: string[],\n\t): ChangedLineRange {\n\t\tlet expandedFirstChanged = firstChanged;\n\t\tlet expandedLastChanged = lastChanged;\n\t\tconst expandForLines = (lines: string[]): void => {\n\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\tif (extractKittyImageIds(lines[i]).length === 0) continue;\n\t\t\t\tconst blockEnd = i + this.getKittyImageReservedRows(lines, i) - 1;\n\t\t\t\tif (i >= firstChanged || (i <= lastChanged && blockEnd >= firstChanged)) {\n\t\t\t\t\texpandedFirstChanged = Math.min(expandedFirstChanged, i);\n\t\t\t\t\texpandedLastChanged = Math.max(expandedLastChanged, blockEnd);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\texpandForLines(this.previousLines);\n\t\texpandForLines(newLines);\n\t\treturn { firstChanged: expandedFirstChanged, lastChanged: expandedLastChanged };\n\t}\n\n\tprivate deleteChangedKittyImages(firstChanged: number, lastChanged: number): string {\n\t\tif (firstChanged < 0 || lastChanged < firstChanged) return \"\";\n\n\t\tconst ids = new Set<number>();\n\t\tconst maxLine = Math.min(lastChanged, this.previousLines.length - 1);\n\t\tfor (let i = firstChanged; i <= maxLine; i++) {\n\t\t\tfor (const id of extractKittyImageIds(this.previousLines[i] ?? \"\")) {\n\t\t\t\tids.add(id);\n\t\t\t}\n\t\t}\n\n\t\treturn this.deleteKittyImages(ids);\n\t}\n\n\tprivate prepareRenderFrame(): MainScreenRenderFrame {\n\t\tconst width = this.terminal.columns;\n\t\tconst height = this.terminal.rows;\n\t\tconst widthChanged = this.previousWidth !== 0 && this.previousWidth !== width;\n\t\tconst heightChanged = this.previousHeight !== 0 && this.previousHeight !== height;\n\t\tconst previousBufferLength = this.previousHeight > 0 ? this.previousViewportTop + this.previousHeight : height;\n\t\tconst previousViewportTop = heightChanged ? Math.max(0, previousBufferLength - height) : this.previousViewportTop;\n\n\t\tlet newLines = this.render(width);\n\t\tif (this.hasOverlayEntries) newLines = this.compositeOverlays(newLines, width, height);\n\t\tconst cursorPosition = this.extractCursorPosition(newLines, height);\n\t\t// Preserve component zone markers for alt-screen navigation, but do not emit\n\t\t// them here: terminals draw their own gutter indicators for OSC 133.\n\t\tnewLines = this.applyLineResets(newLines.map((line) => line.replace(OSC133_ZONE_PREFIX, \"\")));\n\t\treturn { width, height, widthChanged, heightChanged, newLines, cursorPosition, previousViewportTop };\n\t}\n\n\tprivate getLineDiff(\n\t\ttargetRow: number,\n\t\thardwareCursorRow: number,\n\t\tpreviousViewportTop: number,\n\t\tviewportTop: number,\n\t): number {\n\t\tconst currentScreenRow = hardwareCursorRow - previousViewportTop;\n\t\tconst targetScreenRow = targetRow - viewportTop;\n\t\treturn targetScreenRow - currentScreenRow;\n\t}\n\n\tprivate logFullRedraw(frame: MainScreenRenderFrame, reason: string): void {\n\t\tif (process.env.GRIP_DEBUG_REDRAW !== \"1\") return;\n\t\tconst logPath = path.join(this.logDirectory, \"grip-debug.log\");\n\t\tconst message = `[${new Date().toISOString()}] fullRender: ${reason} (prev=${this.previousLines.length}, new=${frame.newLines.length}, height=${frame.height})\\n`;\n\t\tfs.mkdirSync(path.dirname(logPath), { recursive: true });\n\t\tfs.appendFileSync(logPath, message);\n\t}\n\n\tprivate renderFullFrame(frame: MainScreenRenderFrame, clear: boolean): void {\n\t\tthis.fullRedrawCount += 1;\n\t\tlet buffer = \"\\x1b[?2026h\";\n\t\tif (clear) {\n\t\t\tbuffer += this.deleteKittyImages(this.previousKittyImageIds);\n\t\t\tbuffer += \"\\x1b[2J\\x1b[H\\x1b[3J\";\n\t\t}\n\t\tfor (let index = 0; index < frame.newLines.length; index++) {\n\t\t\tif (index > 0) buffer += \"\\r\\n\";\n\t\t\tconst line = frame.newLines[index];\n\t\t\tconst reservedRows = isImageLine(line) ? this.getKittyImageReservedRows(frame.newLines, index) : 1;\n\t\t\tif (reservedRows > 1 && reservedRows <= frame.height) {\n\t\t\t\tbuffer += \"\\r\\n\".repeat(reservedRows - 1);\n\t\t\t\tbuffer += `\\x1b[${reservedRows - 1}A${line}\\x1b[${reservedRows - 1}B`;\n\t\t\t\tindex += reservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbuffer += line;\n\t\t}\n\t\tbuffer += \"\\x1b[?2026l\";\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = Math.max(0, frame.newLines.length - 1);\n\t\tthis.hardwareCursorRow = this.cursorRow;\n\t\tthis.maxLinesRendered = clear ? frame.newLines.length : Math.max(this.maxLinesRendered, frame.newLines.length);\n\t\tconst bufferLength = Math.max(frame.height, frame.newLines.length);\n\t\tthis.previousViewportTop = Math.max(0, bufferLength - frame.height);\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.previousLines = frame.newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(frame.newLines);\n\t\tthis.previousWidth = frame.width;\n\t\tthis.previousHeight = frame.height;\n\t}\n\n\tprivate renderRequiredFullFrame(frame: MainScreenRenderFrame): boolean {\n\t\tif (this.previousLines.length === 0 && !frame.widthChanged && !frame.heightChanged) {\n\t\t\tthis.logFullRedraw(frame, \"first render\");\n\t\t\tthis.renderFullFrame(frame, false);\n\t\t\treturn true;\n\t\t}\n\t\tif (frame.widthChanged) {\n\t\t\tthis.logFullRedraw(frame, `terminal width changed (${this.previousWidth} -> ${frame.width})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\tif (frame.heightChanged && !isTermuxSession()) {\n\t\t\tthis.logFullRedraw(frame, `terminal height changed (${this.previousHeight} -> ${frame.height})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\tif (this.getClearOnShrink() && frame.newLines.length < this.maxLinesRendered && !this.hasOverlayEntries) {\n\t\t\tthis.logFullRedraw(frame, `clearOnShrink (maxLinesRendered=${this.maxLinesRendered})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate findChangedContent(frame: MainScreenRenderFrame): ChangedContentRange | undefined {\n\t\tlet firstChanged = -1;\n\t\tlet lastChanged = -1;\n\t\tconst maxLines = Math.max(frame.newLines.length, this.previousLines.length);\n\t\tfor (let index = 0; index < maxLines; index++) {\n\t\t\tconst oldLine = index < this.previousLines.length ? this.previousLines[index] : \"\";\n\t\t\tconst newLine = index < frame.newLines.length ? frame.newLines[index] : \"\";\n\t\t\tif (oldLine === newLine) continue;\n\t\t\tif (firstChanged === -1) firstChanged = index;\n\t\t\tlastChanged = index;\n\t\t}\n\n\t\tconst appendedLines = frame.newLines.length > this.previousLines.length;\n\t\tif (appendedLines) {\n\t\t\tif (firstChanged === -1) firstChanged = this.previousLines.length;\n\t\t\tlastChanged = frame.newLines.length - 1;\n\t\t}\n\t\tif (firstChanged === -1) return undefined;\n\n\t\tconst expanded = this.expandChangedRangeForKittyImages(firstChanged, lastChanged, frame.newLines);\n\t\treturn {\n\t\t\t...expanded,\n\t\t\tappendStart: appendedLines && expanded.firstChanged === this.previousLines.length && expanded.firstChanged > 0,\n\t\t};\n\t}\n\n\tprivate commitFrameHistory(frame: MainScreenRenderFrame, viewportTop: number): void {\n\t\tthis.previousLines = frame.newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(frame.newLines);\n\t\tthis.previousWidth = frame.width;\n\t\tthis.previousHeight = frame.height;\n\t\tthis.previousViewportTop = viewportTop;\n\t}\n\n\tprivate handleUnchangedFrame(frame: MainScreenRenderFrame): void {\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.previousViewportTop = frame.previousViewportTop;\n\t\tthis.previousHeight = frame.height;\n\t}\n\n\tprivate renderDeletedContent(frame: MainScreenRenderFrame, range: ChangedContentRange): void {\n\t\tif (this.previousLines.length <= frame.newLines.length) {\n\t\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\t\tthis.commitFrameHistory(frame, frame.previousViewportTop);\n\t\t\treturn;\n\t\t}\n\n\t\tlet buffer = \"\\x1b[?2026h\";\n\t\tbuffer += this.deleteChangedKittyImages(range.firstChanged, range.lastChanged);\n\t\tconst targetRow = Math.max(0, frame.newLines.length - 1);\n\t\tif (targetRow < frame.previousViewportTop) {\n\t\t\tthis.logFullRedraw(frame, `deleted lines moved viewport up (${targetRow} < ${frame.previousViewportTop})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\t\tconst lineDiff = this.getLineDiff(\n\t\t\ttargetRow,\n\t\t\tthis.hardwareCursorRow,\n\t\t\tframe.previousViewportTop,\n\t\t\tframe.previousViewportTop,\n\t\t);\n\t\tif (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n\t\telse if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n\t\tbuffer += \"\\r\";\n\t\tconst extraLines = this.previousLines.length - frame.newLines.length;\n\t\tif (extraLines > frame.height) {\n\t\t\tthis.logFullRedraw(frame, `extraLines > height (${extraLines} > ${frame.height})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\t\tconst clearStartOffset = frame.newLines.length === 0 ? 0 : 1;\n\t\tif (extraLines > 0 && clearStartOffset > 0) buffer += `\\x1b[${clearStartOffset}B`;\n\t\tfor (let index = 0; index < extraLines; index++) {\n\t\t\tbuffer += \"\\r\\x1b[2K\";\n\t\t\tif (index < extraLines - 1) buffer += \"\\x1b[1B\";\n\t\t}\n\t\tconst moveBack = Math.max(0, extraLines - 1 + clearStartOffset);\n\t\tif (moveBack > 0) buffer += `\\x1b[${moveBack}A`;\n\t\tbuffer += \"\\x1b[?2026l\";\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = targetRow;\n\t\tthis.hardwareCursorRow = targetRow;\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.commitFrameHistory(frame, frame.previousViewportTop);\n\t}\n\n\tprivate assertRenderedLineFits(line: string, index: number, frame: MainScreenRenderFrame): void {\n\t\tif (isImageLine(line) || visibleWidth(line) <= frame.width) return;\n\t\tconst crashLogPath = path.join(this.logDirectory, \"grip-crash.log\");\n\t\tconst crashData = [\n\t\t\t`Crash at ${new Date().toISOString()}`,\n\t\t\t`Terminal width: ${frame.width}`,\n\t\t\t`Line ${index} visible width: ${visibleWidth(line)}`,\n\t\t\t\"\",\n\t\t\t\"=== All rendered lines ===\",\n\t\t\t...frame.newLines.map(\n\t\t\t\t(renderedLine, lineIndex) => `[${lineIndex}] (w=${visibleWidth(renderedLine)}) ${renderedLine}`,\n\t\t\t),\n\t\t\t\"\",\n\t\t].join(\"\\n\");\n\t\tfs.mkdirSync(path.dirname(crashLogPath), { recursive: true });\n\t\tfs.writeFileSync(crashLogPath, crashData);\n\t\tthis.stop();\n\t\tthrow new Error(\n\t\t\t[\n\t\t\t\t`Rendered line ${index} exceeds terminal width (${visibleWidth(line)} > ${frame.width}).`,\n\t\t\t\t\"\",\n\t\t\t\t\"This is likely caused by a custom TUI component not truncating its output.\",\n\t\t\t\t\"Use visibleWidth() to measure and truncateToWidth() to truncate lines.\",\n\t\t\t\t\"\",\n\t\t\t\t`Debug log written to: ${crashLogPath}`,\n\t\t\t].join(\"\\n\"),\n\t\t);\n\t}\n\n\tprivate renderChangedLines(\n\t\tframe: MainScreenRenderFrame,\n\t\trange: ChangedContentRange,\n\t\tviewportTop: number,\n\t\tinitialBuffer: string,\n\t): ChangedLinesRenderResult | undefined {\n\t\tlet buffer = initialBuffer;\n\t\tconst renderEnd = Math.min(range.lastChanged, frame.newLines.length - 1);\n\t\tfor (let index = range.firstChanged; index <= renderEnd; index++) {\n\t\t\tif (index > range.firstChanged) buffer += \"\\r\\n\";\n\t\t\tconst line = frame.newLines[index];\n\t\t\tconst reservedRows = isImageLine(line) ? this.getKittyImageReservedRows(frame.newLines, index, renderEnd) : 1;\n\t\t\tif (reservedRows > 1) {\n\t\t\t\tconst imageStartScreenRow = index - viewportTop;\n\t\t\t\tif (imageStartScreenRow < 0 || imageStartScreenRow + reservedRows > frame.height) {\n\t\t\t\t\tthis.logFullRedraw(\n\t\t\t\t\t\tframe,\n\t\t\t\t\t\t`kitty image pre-clear would scroll (${imageStartScreenRow} + ${reservedRows} > ${frame.height})`,\n\t\t\t\t\t);\n\t\t\t\t\tthis.renderFullFrame(frame, true);\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tbuffer += \"\\x1b[2K\";\n\t\t\t\tfor (let row = 1; row < reservedRows; row++) buffer += \"\\r\\n\\x1b[2K\";\n\t\t\t\tbuffer += `\\x1b[${reservedRows - 1}A${line}\\x1b[${reservedRows - 1}B`;\n\t\t\t\tindex += reservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbuffer += \"\\x1b[2K\";\n\t\t\tthis.assertRenderedLineFits(line, index, frame);\n\t\t\tbuffer += line;\n\t\t}\n\t\treturn { buffer, renderEnd };\n\t}\n\n\tprivate writeDifferentialDebugLog(\n\t\tframe: MainScreenRenderFrame,\n\t\trange: ChangedContentRange,\n\t\tviewportTop: number,\n\t\thardwareCursorRow: number,\n\t\tlineDiff: number,\n\t\trenderEnd: number,\n\t\tfinalCursorRow: number,\n\t\tbuffer: string,\n\t): void {\n\t\tif (process.env.GRIP_TUI_DEBUG !== \"1\") return;\n\t\tconst debugDir = \"/tmp/tui\";\n\t\tfs.mkdirSync(debugDir, { recursive: true });\n\t\tconst debugPath = path.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);\n\t\tconst debugData = [\n\t\t\t`firstChanged: ${range.firstChanged}`,\n\t\t\t`viewportTop: ${viewportTop}`,\n\t\t\t`cursorRow: ${this.cursorRow}`,\n\t\t\t`height: ${frame.height}`,\n\t\t\t`lineDiff: ${lineDiff}`,\n\t\t\t`hardwareCursorRow: ${hardwareCursorRow}`,\n\t\t\t`renderEnd: ${renderEnd}`,\n\t\t\t`finalCursorRow: ${finalCursorRow}`,\n\t\t\t`cursorPos: ${JSON.stringify(frame.cursorPosition)}`,\n\t\t\t`newLines.length: ${frame.newLines.length}`,\n\t\t\t`previousLines.length: ${this.previousLines.length}`,\n\t\t\t\"\",\n\t\t\t\"=== newLines ===\",\n\t\t\tJSON.stringify(frame.newLines, null, 2),\n\t\t\t\"\",\n\t\t\t\"=== previousLines ===\",\n\t\t\tJSON.stringify(this.previousLines, null, 2),\n\t\t\t\"\",\n\t\t\t\"=== buffer ===\",\n\t\t\tJSON.stringify(buffer),\n\t\t].join(\"\\n\");\n\t\tfs.writeFileSync(debugPath, debugData);\n\t}\n\n\tprivate renderDifferentialContent(frame: MainScreenRenderFrame, range: ChangedContentRange): void {\n\t\tif (range.firstChanged < frame.previousViewportTop) {\n\t\t\tthis.logFullRedraw(frame, `firstChanged < viewportTop (${range.firstChanged} < ${frame.previousViewportTop})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\n\t\tlet previousViewportTop = frame.previousViewportTop;\n\t\tlet viewportTop = previousViewportTop;\n\t\tlet hardwareCursorRow = this.hardwareCursorRow;\n\t\tlet buffer = `\\x1b[?2026h${this.deleteChangedKittyImages(range.firstChanged, range.lastChanged)}`;\n\t\tconst previousViewportBottom = previousViewportTop + frame.height - 1;\n\t\tconst moveTargetRow = range.appendStart ? range.firstChanged - 1 : range.firstChanged;\n\t\tif (moveTargetRow > previousViewportBottom) {\n\t\t\tconst currentScreenRow = Math.max(0, Math.min(frame.height - 1, hardwareCursorRow - previousViewportTop));\n\t\t\tconst moveToBottom = frame.height - 1 - currentScreenRow;\n\t\t\tif (moveToBottom > 0) buffer += `\\x1b[${moveToBottom}B`;\n\t\t\tconst scroll = moveTargetRow - previousViewportBottom;\n\t\t\tbuffer += \"\\r\\n\".repeat(scroll);\n\t\t\tpreviousViewportTop += scroll;\n\t\t\tviewportTop += scroll;\n\t\t\thardwareCursorRow = moveTargetRow;\n\t\t}\n\n\t\tconst lineDiff = this.getLineDiff(moveTargetRow, hardwareCursorRow, previousViewportTop, viewportTop);\n\t\tif (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n\t\telse if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n\t\tbuffer += range.appendStart ? \"\\r\\n\" : \"\\r\";\n\n\t\tconst changedLines = this.renderChangedLines(frame, range, viewportTop, buffer);\n\t\tif (!changedLines) return;\n\t\tbuffer = changedLines.buffer;\n\t\tlet finalCursorRow = changedLines.renderEnd;\n\t\tif (this.previousLines.length > frame.newLines.length) {\n\t\t\tif (changedLines.renderEnd < frame.newLines.length - 1) {\n\t\t\t\tconst moveDown = frame.newLines.length - 1 - changedLines.renderEnd;\n\t\t\t\tbuffer += `\\x1b[${moveDown}B`;\n\t\t\t\tfinalCursorRow = frame.newLines.length - 1;\n\t\t\t}\n\t\t\tconst extraLines = this.previousLines.length - frame.newLines.length;\n\t\t\tfor (let index = frame.newLines.length; index < this.previousLines.length; index++) {\n\t\t\t\tbuffer += \"\\r\\n\\x1b[2K\";\n\t\t\t}\n\t\t\tbuffer += `\\x1b[${extraLines}A`;\n\t\t}\n\t\tbuffer += \"\\x1b[?2026l\";\n\n\t\tthis.writeDifferentialDebugLog(\n\t\t\tframe,\n\t\t\trange,\n\t\t\tviewportTop,\n\t\t\thardwareCursorRow,\n\t\t\tlineDiff,\n\t\t\tchangedLines.renderEnd,\n\t\t\tfinalCursorRow,\n\t\t\tbuffer,\n\t\t);\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = Math.max(0, frame.newLines.length - 1);\n\t\tthis.hardwareCursorRow = finalCursorRow;\n\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, frame.newLines.length);\n\t\tconst committedViewportTop = Math.max(previousViewportTop, finalCursorRow - frame.height + 1);\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.commitFrameHistory(frame, committedViewportTop);\n\t}\n\n\tprotected doRender(): void {\n\t\tif (this.stopped) return;\n\t\tconst frame = this.prepareRenderFrame();\n\t\tif (this.renderRequiredFullFrame(frame)) return;\n\t\tconst changedContent = this.findChangedContent(frame);\n\t\tif (!changedContent) {\n\t\t\tthis.handleUnchangedFrame(frame);\n\t\t\treturn;\n\t\t}\n\t\tif (changedContent.firstChanged >= frame.newLines.length) {\n\t\t\tthis.renderDeletedContent(frame, changedContent);\n\t\t\treturn;\n\t\t}\n\t\tthis.renderDifferentialContent(frame, changedContent);\n\t}\n\n\t/**\n\t * Position the hardware cursor for IME candidate window.\n\t * @param cursorPos The cursor position extracted from rendered output, or null\n\t * @param totalLines Total number of rendered lines\n\t */\n\tprivate positionHardwareCursor(cursorPos: RenderedCursorPosition | null, totalLines: number): void {\n\t\tif (!cursorPos || totalLines <= 0) {\n\t\t\tthis.terminal.hideCursor();\n\t\t\treturn;\n\t\t}\n\n\t\t// Clamp cursor position to valid range\n\t\tconst targetRow = Math.max(0, Math.min(cursorPos.row, totalLines - 1));\n\t\tconst targetCol = Math.max(0, cursorPos.col);\n\n\t\t// Move cursor from current position to target\n\t\tconst rowDelta = targetRow - this.hardwareCursorRow;\n\t\tlet buffer = \"\";\n\t\tif (rowDelta > 0) {\n\t\t\tbuffer += `\\x1b[${rowDelta}B`; // Move down\n\t\t} else if (rowDelta < 0) {\n\t\t\tbuffer += `\\x1b[${-rowDelta}A`; // Move up\n\t\t}\n\t\t// Move to absolute column (1-indexed)\n\t\tbuffer += `\\x1b[${targetCol + 1}G`;\n\n\t\tif (buffer) {\n\t\t\tthis.terminal.write(buffer);\n\t\t}\n\n\t\tthis.hardwareCursorRow = targetRow;\n\t\tif (this.getShowHardwareCursor()) {\n\t\t\tthis.terminal.showCursor();\n\t\t} else {\n\t\t\tthis.terminal.hideCursor();\n\t\t}\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@greppleai/grip-tui",
3
- "version": "0.0.1",
3
+ "version": "0.1.4",
4
4
  "description": "Terminal User Interface library with differential rendering for efficient text-based applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",