gsd-pi 2.64.0-dev.6fe1e44 → 2.64.0-dev.cbb05a1

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.
Files changed (87) hide show
  1. package/dist/headless.js +3 -1
  2. package/dist/resources/extensions/bg-shell/bg-shell-lifecycle.js +22 -7
  3. package/dist/resources/extensions/bg-shell/process-manager.js +6 -1
  4. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +24 -13
  5. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +1 -0
  6. package/dist/resources/extensions/gsd/bootstrap/system-context.js +20 -0
  7. package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +1 -0
  8. package/dist/resources/extensions/gsd/notification-overlay.js +4 -0
  9. package/dist/resources/extensions/gsd/notification-store.js +10 -5
  10. package/dist/web/standalone/.next/BUILD_ID +1 -1
  11. package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -18
  12. package/dist/web/standalone/.next/build-manifest.json +2 -2
  13. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  14. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  15. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  16. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  17. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  18. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  20. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  21. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  22. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  23. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  26. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/index.html +1 -1
  31. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  32. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -18
  38. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  39. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  40. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  41. package/package.json +1 -1
  42. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  43. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  44. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +8 -0
  45. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  46. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +6 -0
  47. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  48. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +36 -0
  49. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  50. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +9 -0
  51. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +33 -0
  52. package/packages/pi-tui/dist/__tests__/overlay-layout.test.d.ts +2 -0
  53. package/packages/pi-tui/dist/__tests__/overlay-layout.test.d.ts.map +1 -0
  54. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +52 -0
  55. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -0
  56. package/packages/pi-tui/dist/components/loader.d.ts +4 -2
  57. package/packages/pi-tui/dist/components/loader.d.ts.map +1 -1
  58. package/packages/pi-tui/dist/components/loader.js +27 -9
  59. package/packages/pi-tui/dist/components/loader.js.map +1 -1
  60. package/packages/pi-tui/dist/components/text.d.ts.map +1 -1
  61. package/packages/pi-tui/dist/components/text.js +2 -0
  62. package/packages/pi-tui/dist/components/text.js.map +1 -1
  63. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
  64. package/packages/pi-tui/dist/overlay-layout.js +11 -1
  65. package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
  66. package/packages/pi-tui/dist/tui.d.ts +4 -0
  67. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  68. package/packages/pi-tui/dist/tui.js +35 -0
  69. package/packages/pi-tui/dist/tui.js.map +1 -1
  70. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +65 -0
  71. package/packages/pi-tui/src/components/loader.ts +27 -10
  72. package/packages/pi-tui/src/components/text.ts +1 -0
  73. package/packages/pi-tui/src/overlay-layout.ts +12 -1
  74. package/packages/pi-tui/src/tui.ts +34 -0
  75. package/src/resources/extensions/bg-shell/bg-shell-lifecycle.ts +19 -7
  76. package/src/resources/extensions/bg-shell/process-manager.ts +8 -2
  77. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +25 -13
  78. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +1 -0
  79. package/src/resources/extensions/gsd/bootstrap/system-context.ts +28 -0
  80. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +1 -0
  81. package/src/resources/extensions/gsd/notification-overlay.ts +5 -0
  82. package/src/resources/extensions/gsd/notification-store.ts +8 -3
  83. package/src/resources/extensions/gsd/tests/complete-slice-string-coercion.test.ts +36 -0
  84. package/src/resources/extensions/gsd/tests/notification-store.test.ts +34 -1
  85. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +163 -0
  86. /package/dist/web/standalone/.next/static/{KPMt-rZBouivKwIKcIral → 6VY044iEgB5gScn5oawg3}/_buildManifest.js +0 -0
  87. /package/dist/web/standalone/.next/static/{KPMt-rZBouivKwIKcIral → 6VY044iEgB5gScn5oawg3}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"tui.js","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Minimal TUI implementation with differential rendering\n */\n\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { isKeyRelease, matchesKey } from \"./keys.js\";\nimport {\n\tapplyLineResets,\n\tcompositeOverlays,\n\textractCursorPosition,\n\tisOverlayVisible as isOverlayEntryVisible,\n} from \"./overlay-layout.js\";\nimport type { Terminal } from \"./terminal.js\";\nimport { getCapabilities, isImageLine, setCellDimensions } from \"./terminal-image.js\";\nimport { truncateToWidth, visibleWidth } from \"./utils.js\";\n\n/**\n * Component interface - all components must implement this\n */\nexport interface Component {\n\t/**\n\t * Render the component to lines for the given viewport width\n\t * @param width - Current viewport width\n\t * @returns Array of strings, each representing a line\n\t */\n\trender(width: number): string[];\n\n\t/**\n\t * Optional handler for keyboard input when component has focus\n\t */\n\thandleInput?(data: string): void;\n\n\t/**\n\t * If true, component receives key release events (Kitty protocol).\n\t * Default is false - release events are filtered out.\n\t */\n\twantsKeyRelease?: boolean;\n\n\t/**\n\t * Invalidate any cached rendering state.\n\t * Called when theme changes or when component needs to re-render from scratch.\n\t */\n\tinvalidate(): void;\n}\n\ntype InputListenerResult = { consume?: boolean; data?: string } | undefined;\ntype InputListener = (data: string) => InputListenerResult;\n\n/**\n * Interface for components that can receive focus and display a hardware cursor.\n * When focused, the component should emit CURSOR_MARKER at the cursor position\n * in its render output. TUI will find this marker and position the hardware\n * cursor there for proper IME candidate window positioning.\n */\nexport interface Focusable {\n\t/** Set by TUI when focus changes. Component should emit CURSOR_MARKER when true. */\n\tfocused: boolean;\n}\n\n/** Type guard to check if a component implements Focusable */\nexport function isFocusable(component: Component | null): component is Component & Focusable {\n\treturn component !== null && \"focused\" in component;\n}\n\n/**\n * Cursor position marker - APC (Application Program Command) sequence.\n * This is a zero-width escape sequence that terminals ignore.\n * Components emit this at the cursor position when focused.\n * TUI finds and strips this marker, then positions the hardware cursor there.\n */\nexport const CURSOR_MARKER = \"\\x1b_pi:c\\x07\";\n\nexport { visibleWidth };\n\n/**\n * Anchor position for overlays\n */\nexport type OverlayAnchor =\n\t| \"center\"\n\t| \"top-left\"\n\t| \"top-right\"\n\t| \"bottom-left\"\n\t| \"bottom-right\"\n\t| \"top-center\"\n\t| \"bottom-center\"\n\t| \"left-center\"\n\t| \"right-center\";\n\n/**\n * Margin configuration for overlays\n */\nexport interface OverlayMargin {\n\ttop?: number;\n\tright?: number;\n\tbottom?: number;\n\tleft?: number;\n}\n\n/** Value that can be absolute (number) or percentage (string like \"50%\") */\nexport type SizeValue = number | `${number}%`;\n\n/**\n * Options for overlay positioning and sizing.\n * Values can be absolute numbers or percentage strings (e.g., \"50%\").\n */\nexport interface OverlayOptions {\n\t// === Sizing ===\n\t/** Width in columns, or percentage of terminal width (e.g., \"50%\") */\n\twidth?: SizeValue;\n\t/** Minimum width in columns */\n\tminWidth?: number;\n\t/** Maximum height in rows, or percentage of terminal height (e.g., \"50%\") */\n\tmaxHeight?: SizeValue;\n\n\t// === Positioning - anchor-based ===\n\t/** Anchor point for positioning (default: 'center') */\n\tanchor?: OverlayAnchor;\n\t/** Horizontal offset from anchor position (positive = right) */\n\toffsetX?: number;\n\t/** Vertical offset from anchor position (positive = down) */\n\toffsetY?: number;\n\n\t// === Positioning - percentage or absolute ===\n\t/** Row position: absolute number, or percentage (e.g., \"25%\" = 25% from top) */\n\trow?: SizeValue;\n\t/** Column position: absolute number, or percentage (e.g., \"50%\" = centered horizontally) */\n\tcol?: SizeValue;\n\n\t// === Margin from terminal edges ===\n\t/** Margin from terminal edges. Number applies to all sides. */\n\tmargin?: OverlayMargin | number;\n\n\t// === Visibility ===\n\t/**\n\t * Control overlay visibility based on terminal dimensions.\n\t * If provided, overlay is only rendered when this returns true.\n\t * Called each render cycle with current terminal dimensions.\n\t */\n\tvisible?: (termWidth: number, termHeight: number) => boolean;\n\t/** If true, don't capture keyboard focus when shown */\n\tnonCapturing?: boolean;\n}\n\n/**\n * Handle returned by showOverlay for controlling the overlay\n */\nexport interface OverlayHandle {\n\t/** Permanently remove the overlay (cannot be shown again) */\n\thide(): void;\n\t/** Temporarily hide or show the overlay */\n\tsetHidden(hidden: boolean): void;\n\t/** Check if overlay is temporarily hidden */\n\tisHidden(): boolean;\n\t/** Focus this overlay and bring it to the visual front */\n\tfocus(): void;\n\t/** Release focus to the previous target */\n\tunfocus(): void;\n\t/** Check if this overlay currently has focus */\n\tisFocused(): boolean;\n}\n\n/**\n * Container - a component that contains other components\n */\nexport class Container implements Component {\n\tchildren: Component[] = [];\n\n\taddChild(component: Component): void {\n\t\tthis.children.push(component);\n\t}\n\n\tremoveChild(component: Component): void {\n\t\tconst index = this.children.indexOf(component);\n\t\tif (index !== -1) {\n\t\t\tthis.children.splice(index, 1);\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tthis.children = [];\n\t}\n\n\tinvalidate(): void {\n\t\tfor (const child of this.children) {\n\t\t\tchild.invalidate?.();\n\t\t}\n\t}\n\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tfor (const child of this.children) {\n\t\t\tconst rendered = child.render(width);\n\t\t\tfor (let i = 0; i < rendered.length; i++) lines.push(rendered[i]);\n\t\t}\n\t\treturn lines;\n\t}\n}\n\n/**\n * TUI - Main class for managing terminal UI with differential rendering\n */\nexport class TUI extends Container {\n\tpublic terminal: Terminal;\n\tprivate previousLines: string[] = [];\n\tprivate previousWidth = 0;\n\tprivate previousHeight = 0;\n\tprivate focusedComponent: Component | null = null;\n\tprivate inputListeners = new Set<InputListener>();\n\n\t/** Global callback for debug key (Shift+Ctrl+D). Called before input is forwarded to focused component. */\n\tpublic onDebug?: () => void;\n\tprivate renderRequested = false;\n\tprivate cursorRow = 0; // Logical cursor row (end of rendered content)\n\tprivate hardwareCursorRow = 0; // Actual terminal cursor row (may differ due to IME positioning)\n\tprivate inputBuffer = \"\"; // Buffer for parsing terminal responses\n\tprivate cellSizeQueryPending = false;\n\tprivate showHardwareCursor = process.env.PI_HARDWARE_CURSOR === \"1\" || process.env.TERM_PROGRAM === \"WarpTerminal\";\n\tprivate clearOnShrink = process.env.PI_CLEAR_ON_SHRINK === \"1\"; // Clear empty rows when content shrinks (default: off)\n\tprivate maxLinesRendered = 0; // Track terminal's working area (max lines ever rendered)\n\tprivate previousViewportTop = 0; // Track previous viewport top for resize-aware cursor moves\n\tprivate fullRedrawCount = 0;\n\tprivate stopped = false;\n\n\t// Overlay stack for modal components rendered on top of base content\n\tprivate focusOrderCounter = 0;\n\tprivate overlayStack: {\n\t\tcomponent: Component;\n\t\toptions?: OverlayOptions;\n\t\tpreFocus: Component | null;\n\t\thidden: boolean;\n\t\tfocusOrder: number;\n\t}[] = [];\n\n\tconstructor(terminal: Terminal, showHardwareCursor?: boolean) {\n\t\tsuper();\n\t\tthis.terminal = terminal;\n\t\tif (showHardwareCursor !== undefined) {\n\t\t\tthis.showHardwareCursor = showHardwareCursor;\n\t\t}\n\t}\n\n\tget fullRedraws(): number {\n\t\treturn this.fullRedrawCount;\n\t}\n\n\tgetShowHardwareCursor(): boolean {\n\t\treturn this.showHardwareCursor;\n\t}\n\n\tsetShowHardwareCursor(enabled: boolean): void {\n\t\tif (this.showHardwareCursor === enabled) return;\n\t\tthis.showHardwareCursor = enabled;\n\t\tif (!enabled) {\n\t\t\tthis.terminal.hideCursor();\n\t\t}\n\t\tthis.requestRender();\n\t}\n\n\tgetClearOnShrink(): boolean {\n\t\treturn this.clearOnShrink;\n\t}\n\n\t/**\n\t * Set whether to trigger full re-render when content shrinks.\n\t * When true (default), empty rows are cleared when content shrinks.\n\t * When false, empty rows remain (reduces redraws on slower terminals).\n\t */\n\tsetClearOnShrink(enabled: boolean): void {\n\t\tthis.clearOnShrink = enabled;\n\t}\n\n\tsetFocus(component: Component | null): void {\n\t\t// Clear focused flag on old component\n\t\tif (isFocusable(this.focusedComponent)) {\n\t\t\tthis.focusedComponent.focused = false;\n\t\t}\n\n\t\tthis.focusedComponent = component;\n\n\t\t// Set focused flag on new component\n\t\tif (isFocusable(component)) {\n\t\t\tcomponent.focused = true;\n\t\t}\n\t}\n\n\t/**\n\t * Show an overlay component with configurable positioning and sizing.\n\t * Returns a handle to control the overlay's visibility.\n\t */\n\tshowOverlay(component: Component, options?: OverlayOptions): OverlayHandle {\n\t\tconst entry = {\n\t\t\tcomponent,\n\t\t\toptions,\n\t\t\tpreFocus: this.focusedComponent,\n\t\t\thidden: false,\n\t\t\tfocusOrder: ++this.focusOrderCounter,\n\t\t};\n\t\tthis.overlayStack.push(entry);\n\t\t// Only focus if overlay is actually visible\n\t\tif (!options?.nonCapturing && this.isOverlayVisible(entry)) {\n\t\t\tthis.setFocus(component);\n\t\t}\n\t\tthis.terminal.hideCursor();\n\t\tthis.requestRender();\n\n\t\t// Return handle for controlling this overlay\n\t\treturn {\n\t\t\thide: () => {\n\t\t\t\tconst index = this.overlayStack.indexOf(entry);\n\t\t\t\tif (index !== -1) {\n\t\t\t\t\tthis.overlayStack.splice(index, 1);\n\t\t\t\t\t// Restore focus if this overlay had focus\n\t\t\t\t\tif (this.focusedComponent === component) {\n\t\t\t\t\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\t\t\t\t\tthis.setFocus(topVisible?.component ?? entry.preFocus);\n\t\t\t\t\t}\n\t\t\t\t\tif (this.overlayStack.length === 0) this.terminal.hideCursor();\n\t\t\t\t\tthis.requestRender();\n\t\t\t\t}\n\t\t\t},\n\t\t\tsetHidden: (hidden: boolean) => {\n\t\t\t\tif (entry.hidden === hidden) return;\n\t\t\t\tentry.hidden = hidden;\n\t\t\t\t// Update focus when hiding/showing\n\t\t\t\tif (hidden) {\n\t\t\t\t\t// If this overlay had focus, move focus to next visible or preFocus\n\t\t\t\t\tif (this.focusedComponent === component) {\n\t\t\t\t\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\t\t\t\t\tthis.setFocus(topVisible?.component ?? entry.preFocus);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Restore focus to this overlay when showing (if it's actually visible)\n\t\t\t\t\tif (!options?.nonCapturing && this.isOverlayVisible(entry)) {\n\t\t\t\t\t\tentry.focusOrder = ++this.focusOrderCounter;\n\t\t\t\t\t\tthis.setFocus(component);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.requestRender();\n\t\t\t},\n\t\t\tisHidden: () => entry.hidden,\n\t\t\tfocus: () => {\n\t\t\t\tif (!this.overlayStack.includes(entry) || !this.isOverlayVisible(entry)) return;\n\t\t\t\tif (this.focusedComponent !== component) {\n\t\t\t\t\tthis.setFocus(component);\n\t\t\t\t}\n\t\t\t\tentry.focusOrder = ++this.focusOrderCounter;\n\t\t\t\tthis.requestRender();\n\t\t\t},\n\t\t\tunfocus: () => {\n\t\t\t\tif (this.focusedComponent !== component) return;\n\t\t\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\t\t\tthis.setFocus(topVisible && topVisible !== entry ? topVisible.component : entry.preFocus);\n\t\t\t\tthis.requestRender();\n\t\t\t},\n\t\t\tisFocused: () => this.focusedComponent === component,\n\t\t};\n\t}\n\n\t/** Hide the topmost overlay and restore previous focus. */\n\thideOverlay(): void {\n\t\tconst overlay = this.overlayStack.pop();\n\t\tif (!overlay) return;\n\t\tif (this.focusedComponent === overlay.component) {\n\t\t\t// Find topmost visible overlay, or fall back to preFocus\n\t\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\t\tthis.setFocus(topVisible?.component ?? overlay.preFocus);\n\t\t}\n\t\tif (this.overlayStack.length === 0) this.terminal.hideCursor();\n\t\tthis.requestRender();\n\t}\n\n\t/** Check if there are any visible overlays */\n\thasOverlay(): boolean {\n\t\treturn this.overlayStack.some((o) => this.isOverlayVisible(o));\n\t}\n\n\t/** Check if an overlay entry is currently visible */\n\tprivate isOverlayVisible(entry: (typeof this.overlayStack)[number]): boolean {\n\t\treturn isOverlayEntryVisible(entry, this.terminal.columns, this.terminal.rows);\n\t}\n\n\t/** Find the topmost visible capturing overlay, if any */\n\tprivate getTopmostVisibleOverlay(): (typeof this.overlayStack)[number] | undefined {\n\t\tfor (let i = this.overlayStack.length - 1; i >= 0; i--) {\n\t\t\tif (this.overlayStack[i].options?.nonCapturing) continue;\n\t\t\tif (this.isOverlayVisible(this.overlayStack[i])) {\n\t\t\t\treturn this.overlayStack[i];\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tfor (const overlay of this.overlayStack) overlay.component.invalidate?.();\n\t}\n\n\tstart(): void {\n\t\tthis.stopped = false;\n\t\t// Non-TTY stdout (pipe) — skip TUI entirely to avoid burning CPU.\n\t\t// RPC bridge processes have piped stdio; rendering ANSI escape codes\n\t\t// to a pipe is pure waste and causes a runaway render loop. (issue #3095)\n\t\tif (!this.terminal.isTTY) {\n\t\t\treturn;\n\t\t}\n\t\tthis.terminal.start(\n\t\t\t(data) => this.handleInput(data),\n\t\t\t() => this.requestRender(),\n\t\t);\n\t\tthis.terminal.hideCursor();\n\t\tthis.queryCellSize();\n\t\tthis.requestRender();\n\t}\n\n\taddInputListener(listener: InputListener): () => void {\n\t\tthis.inputListeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.inputListeners.delete(listener);\n\t\t};\n\t}\n\n\tremoveInputListener(listener: InputListener): void {\n\t\tthis.inputListeners.delete(listener);\n\t}\n\n\tprivate queryCellSize(): void {\n\t\t// Only query if terminal supports images (cell size is only used for image rendering)\n\t\tif (!getCapabilities().images) {\n\t\t\treturn;\n\t\t}\n\t\t// Query terminal for cell size in pixels: CSI 16 t\n\t\t// Response format: CSI 6 ; height ; width t\n\t\tthis.cellSizeQueryPending = true;\n\t\tthis.terminal.write(\"\\x1b[16t\");\n\t}\n\n\tstop(): void {\n\t\tthis.stopped = true;\n\n\t\t// Dispose all overlays to stop any running timers\n\t\tfor (const entry of this.overlayStack) {\n\t\t\tif (\"dispose\" in entry.component && typeof (entry.component as any).dispose === \"function\") {\n\t\t\t\t(entry.component as any).dispose();\n\t\t\t}\n\t\t}\n\t\tthis.overlayStack = [];\n\n\t\t// Move cursor to the end of the content to prevent overwriting/artifacts on exit\n\t\tif (this.previousLines.length > 0) {\n\t\t\tconst targetRow = this.previousLines.length; // Line after the last content\n\t\t\tconst lineDiff = targetRow - this.hardwareCursorRow;\n\t\t\tif (lineDiff > 0) {\n\t\t\t\tthis.terminal.write(`\\x1b[${lineDiff}B`);\n\t\t\t} else if (lineDiff < 0) {\n\t\t\t\tthis.terminal.write(`\\x1b[${-lineDiff}A`);\n\t\t\t}\n\t\t\tthis.terminal.write(\"\\r\\n\");\n\t\t}\n\n\t\tthis.terminal.showCursor();\n\t\tthis.terminal.stop();\n\t}\n\n\trequestRender(force = false): void {\n\t\t// Skip rendering on non-TTY stdout to prevent CPU burn (issue #3095)\n\t\tif (!this.terminal.isTTY) return;\n\t\tif (force) {\n\t\t\tthis.previousLines = [];\n\t\t\tthis.previousWidth = -1; // -1 triggers widthChanged, forcing a full clear\n\t\t\tthis.previousHeight = -1; // -1 triggers heightChanged, forcing a full clear\n\t\t\tthis.cursorRow = 0;\n\t\t\tthis.hardwareCursorRow = 0;\n\t\t\tthis.maxLinesRendered = 0;\n\t\t\tthis.previousViewportTop = 0;\n\t\t}\n\t\tif (this.renderRequested) return;\n\t\tthis.renderRequested = true;\n\t\tprocess.nextTick(() => {\n\t\t\tthis.renderRequested = false;\n\t\t\tthis.doRender();\n\t\t});\n\t}\n\n\tprivate handleInput(data: string): void {\n\t\tif (this.inputListeners.size > 0) {\n\t\t\tlet current = data;\n\t\t\tfor (const listener of this.inputListeners) {\n\t\t\t\tconst result = listener(current);\n\t\t\t\tif (result?.consume) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (result?.data !== undefined) {\n\t\t\t\t\tcurrent = result.data;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (current.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdata = current;\n\t\t}\n\n\t\t// If we're waiting for cell size response, buffer input and parse\n\t\tif (this.cellSizeQueryPending) {\n\t\t\tthis.inputBuffer += data;\n\t\t\tconst filtered = this.parseCellSizeResponse();\n\t\t\tif (filtered.length === 0) return;\n\t\t\tdata = filtered;\n\t\t}\n\n\t\t// Global debug key handler (Shift+Ctrl+D)\n\t\tif (matchesKey(data, \"shift+ctrl+d\") && this.onDebug) {\n\t\t\tthis.onDebug();\n\t\t\treturn;\n\t\t}\n\n\t\t// If focused component is an overlay, verify it's still visible\n\t\t// (visibility can change due to terminal resize or visible() callback)\n\t\tconst focusedOverlay = this.overlayStack.find((o) => o.component === this.focusedComponent);\n\t\tif (focusedOverlay && !this.isOverlayVisible(focusedOverlay)) {\n\t\t\t// Focused overlay is no longer visible, redirect to topmost visible overlay\n\t\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\t\tif (topVisible) {\n\t\t\t\tthis.setFocus(topVisible.component);\n\t\t\t} else {\n\t\t\t\t// No visible overlays, restore to preFocus\n\t\t\t\tthis.setFocus(focusedOverlay.preFocus);\n\t\t\t}\n\t\t}\n\n\t\t// Pass input to focused component (including Ctrl+C)\n\t\t// The focused component can decide how to handle Ctrl+C\n\t\tif (this.focusedComponent?.handleInput) {\n\t\t\t// Filter out key release events unless component opts in\n\t\t\tif (isKeyRelease(data) && !this.focusedComponent.wantsKeyRelease) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.focusedComponent.handleInput(data);\n\t\t\tthis.requestRender();\n\t\t}\n\t}\n\n\tprivate parseCellSizeResponse(): string {\n\t\t// Response format: ESC [ 6 ; height ; width t\n\t\t// Match the response pattern\n\t\tconst responsePattern = /\\x1b\\[6;(\\d+);(\\d+)t/;\n\t\tconst match = this.inputBuffer.match(responsePattern);\n\n\t\tif (match) {\n\t\t\tconst heightPx = parseInt(match[1], 10);\n\t\t\tconst widthPx = parseInt(match[2], 10);\n\n\t\t\tif (heightPx > 0 && widthPx > 0) {\n\t\t\t\tsetCellDimensions({ widthPx, heightPx });\n\t\t\t\t// Invalidate all components so images re-render with correct dimensions\n\t\t\t\tthis.invalidate();\n\t\t\t\tthis.requestRender();\n\t\t\t}\n\n\t\t\t// Remove the response from buffer\n\t\t\tthis.inputBuffer = this.inputBuffer.replace(responsePattern, \"\");\n\t\t\tthis.cellSizeQueryPending = false;\n\t\t}\n\n\t\t// Check if we have a partial cell size response starting (wait for more data)\n\t\t// Patterns that could be incomplete cell size response: \\x1b, \\x1b[, \\x1b[6, \\x1b[6;...(no t yet)\n\t\tconst partialCellSizePattern = /\\x1b(\\[6?;?[\\d;]*)?$/;\n\t\tif (partialCellSizePattern.test(this.inputBuffer)) {\n\t\t\t// Check if it's actually a complete different escape sequence (ends with a letter)\n\t\t\t// Cell size response ends with 't', Kitty keyboard ends with 'u', arrows end with A-D, etc.\n\t\t\tconst lastChar = this.inputBuffer[this.inputBuffer.length - 1];\n\t\t\tif (!/[a-zA-Z~]/.test(lastChar)) {\n\t\t\t\t// Doesn't end with a terminator, might be incomplete - wait for more\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t}\n\n\t\t// No cell size response found, return buffered data as user input\n\t\tconst result = this.inputBuffer;\n\t\tthis.inputBuffer = \"\";\n\t\tthis.cellSizeQueryPending = false; // Give up waiting\n\t\treturn result;\n\t}\n\n\tprivate doRender(): void {\n\t\tif (this.stopped) return;\n\t\tconst width = this.terminal.columns;\n\t\tconst height = this.terminal.rows;\n\t\tlet viewportTop = Math.max(0, this.maxLinesRendered - height);\n\t\tlet prevViewportTop = this.previousViewportTop;\n\t\tlet hardwareCursorRow = this.hardwareCursorRow;\n\t\tconst computeLineDiff = (targetRow: number): number => {\n\t\t\tconst currentScreenRow = hardwareCursorRow - prevViewportTop;\n\t\t\tconst targetScreenRow = targetRow - viewportTop;\n\t\t\treturn targetScreenRow - currentScreenRow;\n\t\t};\n\n\t\t// Render all components to get new lines\n\t\tlet newLines = this.render(width);\n\n\t\t// Composite overlays into the rendered lines (before differential compare)\n\t\tif (this.overlayStack.length > 0) {\n\t\t\tnewLines = compositeOverlays(newLines, this.overlayStack, width, height, this.maxLinesRendered);\n\t\t}\n\n\t\t// Extract cursor position before applying line resets (marker must be found first)\n\t\tconst cursorPos = extractCursorPosition(newLines, height);\n\n\t\tnewLines = applyLineResets(newLines);\n\n\t\t// Width or height changed - need full re-render\n\t\tconst widthChanged = this.previousWidth !== 0 && this.previousWidth !== width;\n\t\tconst heightChanged = this.previousHeight !== 0 && this.previousHeight !== height;\n\n\t\t// Helper to clear scrollback and viewport and render all new lines\n\t\tconst fullRender = (clear: boolean): void => {\n\t\t\tthis.fullRedrawCount += 1;\n\t\t\tlet buffer = \"\\x1b[?2026h\"; // Begin synchronized output\n\t\t\tif (clear) buffer += \"\\x1b[2J\\x1b[H\"; // Clear screen and home (no scrollback clear — preserves view position)\n\t\t\tfor (let i = 0; i < newLines.length; i++) {\n\t\t\t\tif (i > 0) buffer += \"\\r\\n\";\n\t\t\t\tlet line = newLines[i];\n\t\t\t\tif (!isImageLine(line) && visibleWidth(line) > width) {\n\t\t\t\t\tline = truncateToWidth(line, width);\n\t\t\t\t}\n\t\t\t\tbuffer += line;\n\t\t\t}\n\t\t\tbuffer += \"\\x1b[?2026l\"; // End synchronized output\n\t\t\tthis.terminal.write(buffer);\n\t\t\tthis.cursorRow = Math.max(0, newLines.length - 1);\n\t\t\tthis.hardwareCursorRow = this.cursorRow;\n\t\t\t// Reset max lines when clearing, otherwise track growth\n\t\t\tif (clear) {\n\t\t\t\tthis.maxLinesRendered = newLines.length;\n\t\t\t} else {\n\t\t\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, newLines.length);\n\t\t\t}\n\t\t\tthis.previousViewportTop = Math.max(0, this.maxLinesRendered - height);\n\t\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\t\t\tthis.previousLines = newLines;\n\t\t\tthis.previousWidth = width;\n\t\t\tthis.previousHeight = height;\n\t\t};\n\n\t\tconst debugRedraw = process.env.PI_DEBUG_REDRAW === \"1\";\n\t\tconst logRedraw = (reason: string): void => {\n\t\t\tif (!debugRedraw) return;\n\t\t\tconst logPath = path.join(os.homedir(), \".pi\", \"agent\", \"pi-debug.log\");\n\t\t\tconst msg = `[${new Date().toISOString()}] fullRender: ${reason} (prev=${this.previousLines.length}, new=${newLines.length}, height=${height})\\n`;\n\t\t\tfs.appendFileSync(logPath, msg);\n\t\t};\n\n\t\t// First render - just output everything without clearing (assumes clean screen)\n\t\tif (this.previousLines.length === 0 && !widthChanged && !heightChanged) {\n\t\t\tlogRedraw(\"first render\");\n\t\t\tfullRender(false);\n\t\t\treturn;\n\t\t}\n\n\t\t// Width or height changed - full re-render\n\t\tif (widthChanged || heightChanged) {\n\t\t\tlogRedraw(`terminal size changed (${this.previousWidth}x${this.previousHeight} -> ${width}x${height})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Content shrunk below the working area and no overlays - re-render to clear empty rows\n\t\t// (overlays need the padding, so only do this when no overlays are active)\n\t\t// Configurable via setClearOnShrink() or PI_CLEAR_ON_SHRINK=0 env var\n\t\tif (this.clearOnShrink && newLines.length < this.maxLinesRendered && this.overlayStack.length === 0) {\n\t\t\tlogRedraw(`clearOnShrink (maxLinesRendered=${this.maxLinesRendered})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Find first and last changed lines\n\t\tlet firstChanged = -1;\n\t\tlet lastChanged = -1;\n\t\tconst maxLines = Math.max(newLines.length, this.previousLines.length);\n\t\tfor (let i = 0; i < maxLines; i++) {\n\t\t\tconst oldLine = i < this.previousLines.length ? this.previousLines[i] : \"\";\n\t\t\tconst newLine = i < newLines.length ? newLines[i] : \"\";\n\n\t\t\tif (oldLine !== newLine) {\n\t\t\t\tif (firstChanged === -1) {\n\t\t\t\t\tfirstChanged = i;\n\t\t\t\t}\n\t\t\t\tlastChanged = i;\n\t\t\t}\n\t\t}\n\t\tconst appendedLines = newLines.length > this.previousLines.length;\n\t\tif (appendedLines) {\n\t\t\tif (firstChanged === -1) {\n\t\t\t\tfirstChanged = this.previousLines.length;\n\t\t\t}\n\t\t\tlastChanged = newLines.length - 1;\n\t\t}\n\t\tconst appendStart = appendedLines && firstChanged === this.previousLines.length && firstChanged > 0;\n\n\t\t// No changes - but still need to update hardware cursor position if it moved\n\t\tif (firstChanged === -1) {\n\t\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\t\t\tthis.previousViewportTop = Math.max(0, this.maxLinesRendered - height);\n\t\t\tthis.previousHeight = height;\n\t\t\treturn;\n\t\t}\n\n\t\t// All changes are in deleted lines (nothing to render, just clear)\n\t\tif (firstChanged >= newLines.length) {\n\t\t\tif (this.previousLines.length > newLines.length) {\n\t\t\t\tlet buffer = \"\\x1b[?2026h\";\n\t\t\t\t// Move to end of new content (clamp to 0 for empty content)\n\t\t\t\tconst targetRow = Math.max(0, newLines.length - 1);\n\t\t\t\tconst lineDiff = computeLineDiff(targetRow);\n\t\t\t\tif (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n\t\t\t\telse if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n\t\t\t\tbuffer += \"\\r\";\n\t\t\t\t// Clear extra lines without scrolling\n\t\t\t\tconst extraLines = this.previousLines.length - newLines.length;\n\t\t\t\tif (extraLines > height) {\n\t\t\t\t\tlogRedraw(`extraLines > height (${extraLines} > ${height})`);\n\t\t\t\t\tfullRender(true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (extraLines > 0) {\n\t\t\t\t\tbuffer += \"\\x1b[1B\";\n\t\t\t\t}\n\t\t\t\tfor (let i = 0; i < extraLines; i++) {\n\t\t\t\t\tbuffer += \"\\r\\x1b[2K\";\n\t\t\t\t\tif (i < extraLines - 1) buffer += \"\\x1b[1B\";\n\t\t\t\t}\n\t\t\t\tif (extraLines > 0) {\n\t\t\t\t\tbuffer += `\\x1b[${extraLines}A`;\n\t\t\t\t}\n\t\t\t\tbuffer += \"\\x1b[?2026l\";\n\t\t\t\tthis.terminal.write(buffer);\n\t\t\t\tthis.cursorRow = targetRow;\n\t\t\t\tthis.hardwareCursorRow = targetRow;\n\t\t\t}\n\t\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\t\t\tthis.previousLines = newLines;\n\t\t\tthis.previousWidth = width;\n\t\t\tthis.previousHeight = height;\n\t\t\tthis.previousViewportTop = Math.max(0, this.maxLinesRendered - height);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if firstChanged is above what was previously visible\n\t\t// Use previousLines.length (not maxLinesRendered) to avoid false positives after content shrinks\n\t\tconst previousContentViewportTop = Math.max(0, this.previousLines.length - height);\n\t\tif (firstChanged < previousContentViewportTop) {\n\t\t\t// First change is above previous viewport - need full re-render\n\t\t\tlogRedraw(`firstChanged < viewportTop (${firstChanged} < ${previousContentViewportTop})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Render from first changed line to end\n\t\t// Build buffer with all updates wrapped in synchronized output\n\t\tlet buffer = \"\\x1b[?2026h\"; // Begin synchronized output\n\t\tconst prevViewportBottom = prevViewportTop + height - 1;\n\t\tconst moveTargetRow = appendStart ? firstChanged - 1 : firstChanged;\n\t\tif (moveTargetRow > prevViewportBottom) {\n\t\t\tconst currentScreenRow = Math.max(0, Math.min(height - 1, hardwareCursorRow - prevViewportTop));\n\t\t\tconst moveToBottom = height - 1 - currentScreenRow;\n\t\t\tif (moveToBottom > 0) {\n\t\t\t\tbuffer += `\\x1b[${moveToBottom}B`;\n\t\t\t}\n\t\t\tconst scroll = moveTargetRow - prevViewportBottom;\n\t\t\tbuffer += \"\\r\\n\".repeat(scroll);\n\t\t\tprevViewportTop += scroll;\n\t\t\tviewportTop += scroll;\n\t\t\thardwareCursorRow = moveTargetRow;\n\t\t}\n\n\t\t// Move cursor to first changed line (use hardwareCursorRow for actual position)\n\t\tconst lineDiff = computeLineDiff(moveTargetRow);\n\t\tif (lineDiff > 0) {\n\t\t\tbuffer += `\\x1b[${lineDiff}B`; // Move down\n\t\t} else if (lineDiff < 0) {\n\t\t\tbuffer += `\\x1b[${-lineDiff}A`; // Move up\n\t\t}\n\n\t\tbuffer += appendStart ? \"\\r\\n\" : \"\\r\"; // Move to column 0\n\n\t\t// Only render changed lines (firstChanged to lastChanged), not all lines to end\n\t\t// This reduces flicker when only a single line changes (e.g., spinner animation)\n\t\tconst renderEnd = Math.min(lastChanged, newLines.length - 1);\n\t\tfor (let i = firstChanged; i <= renderEnd; i++) {\n\t\t\tif (i > firstChanged) buffer += \"\\r\\n\";\n\t\t\tbuffer += \"\\x1b[2K\"; // Clear current line\n\t\t\tlet line = newLines[i];\n\t\t\tconst isImage = isImageLine(line);\n\t\t\tif (!isImage && visibleWidth(line) > width) {\n\t\t\t\tline = truncateToWidth(line, width);\n\t\t\t}\n\t\t\tbuffer += line;\n\t\t}\n\n\t\t// Track where cursor ended up after rendering\n\t\tlet finalCursorRow = renderEnd;\n\n\t\t// If we had more lines before, clear them and move cursor back\n\t\tif (this.previousLines.length > newLines.length) {\n\t\t\t// Move to end of new content first if we stopped before it\n\t\t\tif (renderEnd < newLines.length - 1) {\n\t\t\t\tconst moveDown = newLines.length - 1 - renderEnd;\n\t\t\t\tbuffer += `\\x1b[${moveDown}B`;\n\t\t\t\tfinalCursorRow = newLines.length - 1;\n\t\t\t}\n\t\t\tconst extraLines = this.previousLines.length - newLines.length;\n\t\t\tfor (let i = newLines.length; i < this.previousLines.length; i++) {\n\t\t\t\tbuffer += \"\\r\\n\\x1b[2K\";\n\t\t\t}\n\t\t\t// Move cursor back to end of new content\n\t\t\tbuffer += `\\x1b[${extraLines}A`;\n\t\t}\n\n\t\tbuffer += \"\\x1b[?2026l\"; // End synchronized output\n\n\t\tif (process.env.PI_TUI_DEBUG === \"1\") {\n\t\t\tconst debugDir = path.join(os.tmpdir(), \"tui\");\n\t\t\tfs.mkdirSync(debugDir, { recursive: true });\n\t\t\tconst debugPath = path.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);\n\t\t\tconst debugData = [\n\t\t\t\t`firstChanged: ${firstChanged}`,\n\t\t\t\t`viewportTop: ${viewportTop}`,\n\t\t\t\t`cursorRow: ${this.cursorRow}`,\n\t\t\t\t`height: ${height}`,\n\t\t\t\t`lineDiff: ${lineDiff}`,\n\t\t\t\t`hardwareCursorRow: ${hardwareCursorRow}`,\n\t\t\t\t`renderEnd: ${renderEnd}`,\n\t\t\t\t`finalCursorRow: ${finalCursorRow}`,\n\t\t\t\t`cursorPos: ${JSON.stringify(cursorPos)}`,\n\t\t\t\t`newLines.length: ${newLines.length}`,\n\t\t\t\t`previousLines.length: ${this.previousLines.length}`,\n\t\t\t\t\"\",\n\t\t\t\t\"=== newLines ===\",\n\t\t\t\tJSON.stringify(newLines, null, 2),\n\t\t\t\t\"\",\n\t\t\t\t\"=== previousLines ===\",\n\t\t\t\tJSON.stringify(this.previousLines, null, 2),\n\t\t\t\t\"\",\n\t\t\t\t\"=== buffer ===\",\n\t\t\t\tJSON.stringify(buffer),\n\t\t\t].join(\"\\n\");\n\t\t\tfs.writeFileSync(debugPath, debugData);\n\t\t}\n\n\t\t// Write entire buffer at once\n\t\tthis.terminal.write(buffer);\n\n\t\t// Track cursor position for next render\n\t\t// cursorRow tracks end of content (for viewport calculation)\n\t\t// hardwareCursorRow tracks actual terminal cursor position (for movement)\n\t\tthis.cursorRow = Math.max(0, newLines.length - 1);\n\t\tthis.hardwareCursorRow = finalCursorRow;\n\t\t// Track terminal's working area (grows but doesn't shrink unless cleared)\n\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, newLines.length);\n\t\tthis.previousViewportTop = Math.max(0, this.maxLinesRendered - height);\n\n\t\t// Position hardware cursor for IME\n\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\n\t\tthis.previousLines = newLines;\n\t\tthis.previousWidth = width;\n\t\tthis.previousHeight = height;\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: { row: number; col: number } | 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.showHardwareCursor) {\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.js","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Minimal TUI implementation with differential rendering\n */\n\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { isKeyRelease, matchesKey } from \"./keys.js\";\nimport {\n\tapplyLineResets,\n\tcompositeOverlays,\n\textractCursorPosition,\n\tisOverlayVisible as isOverlayEntryVisible,\n} from \"./overlay-layout.js\";\nimport type { Terminal } from \"./terminal.js\";\nimport { getCapabilities, isImageLine, setCellDimensions } from \"./terminal-image.js\";\nimport { truncateToWidth, visibleWidth } from \"./utils.js\";\n\n/**\n * Component interface - all components must implement this\n */\nexport interface Component {\n\t/**\n\t * Render the component to lines for the given viewport width\n\t * @param width - Current viewport width\n\t * @returns Array of strings, each representing a line\n\t */\n\trender(width: number): string[];\n\n\t/**\n\t * Optional handler for keyboard input when component has focus\n\t */\n\thandleInput?(data: string): void;\n\n\t/**\n\t * If true, component receives key release events (Kitty protocol).\n\t * Default is false - release events are filtered out.\n\t */\n\twantsKeyRelease?: boolean;\n\n\t/**\n\t * Invalidate any cached rendering state.\n\t * Called when theme changes or when component needs to re-render from scratch.\n\t */\n\tinvalidate(): void;\n}\n\ntype InputListenerResult = { consume?: boolean; data?: string } | undefined;\ntype InputListener = (data: string) => InputListenerResult;\n\n/**\n * Interface for components that can receive focus and display a hardware cursor.\n * When focused, the component should emit CURSOR_MARKER at the cursor position\n * in its render output. TUI will find this marker and position the hardware\n * cursor there for proper IME candidate window positioning.\n */\nexport interface Focusable {\n\t/** Set by TUI when focus changes. Component should emit CURSOR_MARKER when true. */\n\tfocused: boolean;\n}\n\n/** Type guard to check if a component implements Focusable */\nexport function isFocusable(component: Component | null): component is Component & Focusable {\n\treturn component !== null && \"focused\" in component;\n}\n\n/**\n * Cursor position marker - APC (Application Program Command) sequence.\n * This is a zero-width escape sequence that terminals ignore.\n * Components emit this at the cursor position when focused.\n * TUI finds and strips this marker, then positions the hardware cursor there.\n */\nexport const CURSOR_MARKER = \"\\x1b_pi:c\\x07\";\n\nexport { visibleWidth };\n\n/**\n * Anchor position for overlays\n */\nexport type OverlayAnchor =\n\t| \"center\"\n\t| \"top-left\"\n\t| \"top-right\"\n\t| \"bottom-left\"\n\t| \"bottom-right\"\n\t| \"top-center\"\n\t| \"bottom-center\"\n\t| \"left-center\"\n\t| \"right-center\";\n\n/**\n * Margin configuration for overlays\n */\nexport interface OverlayMargin {\n\ttop?: number;\n\tright?: number;\n\tbottom?: number;\n\tleft?: number;\n}\n\n/** Value that can be absolute (number) or percentage (string like \"50%\") */\nexport type SizeValue = number | `${number}%`;\n\n/**\n * Options for overlay positioning and sizing.\n * Values can be absolute numbers or percentage strings (e.g., \"50%\").\n */\nexport interface OverlayOptions {\n\t// === Sizing ===\n\t/** Width in columns, or percentage of terminal width (e.g., \"50%\") */\n\twidth?: SizeValue;\n\t/** Minimum width in columns */\n\tminWidth?: number;\n\t/** Maximum height in rows, or percentage of terminal height (e.g., \"50%\") */\n\tmaxHeight?: SizeValue;\n\n\t// === Positioning - anchor-based ===\n\t/** Anchor point for positioning (default: 'center') */\n\tanchor?: OverlayAnchor;\n\t/** Horizontal offset from anchor position (positive = right) */\n\toffsetX?: number;\n\t/** Vertical offset from anchor position (positive = down) */\n\toffsetY?: number;\n\n\t// === Positioning - percentage or absolute ===\n\t/** Row position: absolute number, or percentage (e.g., \"25%\" = 25% from top) */\n\trow?: SizeValue;\n\t/** Column position: absolute number, or percentage (e.g., \"50%\" = centered horizontally) */\n\tcol?: SizeValue;\n\n\t// === Margin from terminal edges ===\n\t/** Margin from terminal edges. Number applies to all sides. */\n\tmargin?: OverlayMargin | number;\n\n\t// === Visibility ===\n\t/**\n\t * Control overlay visibility based on terminal dimensions.\n\t * If provided, overlay is only rendered when this returns true.\n\t * Called each render cycle with current terminal dimensions.\n\t */\n\tvisible?: (termWidth: number, termHeight: number) => boolean;\n\t/** If true, don't capture keyboard focus when shown */\n\tnonCapturing?: boolean;\n\t/** If true, dim the background behind the overlay */\n\tbackdrop?: boolean;\n}\n\n/**\n * Handle returned by showOverlay for controlling the overlay\n */\nexport interface OverlayHandle {\n\t/** Permanently remove the overlay (cannot be shown again) */\n\thide(): void;\n\t/** Temporarily hide or show the overlay */\n\tsetHidden(hidden: boolean): void;\n\t/** Check if overlay is temporarily hidden */\n\tisHidden(): boolean;\n\t/** Focus this overlay and bring it to the visual front */\n\tfocus(): void;\n\t/** Release focus to the previous target */\n\tunfocus(): void;\n\t/** Check if this overlay currently has focus */\n\tisFocused(): boolean;\n}\n\n/**\n * Container - a component that contains other components\n */\nexport class Container implements Component {\n\tchildren: Component[] = [];\n\tprivate _prevRender: string[] | null = null;\n\n\taddChild(component: Component): void {\n\t\tthis.children.push(component);\n\t\tthis._prevRender = null;\n\t}\n\n\tremoveChild(component: Component): void {\n\t\tconst index = this.children.indexOf(component);\n\t\tif (index !== -1) {\n\t\t\tconst child = this.children[index];\n\t\t\tthis.children.splice(index, 1);\n\t\t\tif ('dispose' in child && typeof (child as any).dispose === 'function') {\n\t\t\t\t(child as any).dispose();\n\t\t\t}\n\t\t\tthis._prevRender = null;\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tfor (const child of this.children) {\n\t\t\tif ('dispose' in child && typeof (child as any).dispose === 'function') {\n\t\t\t\t(child as any).dispose();\n\t\t\t}\n\t\t}\n\t\tthis.children = [];\n\t\tthis._prevRender = null;\n\t}\n\n\tinvalidate(): void {\n\t\tfor (const child of this.children) {\n\t\t\tchild.invalidate?.();\n\t\t}\n\t}\n\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tfor (const child of this.children) {\n\t\t\tconst rendered = child.render(width);\n\t\t\tfor (let i = 0; i < rendered.length; i++) lines.push(rendered[i]);\n\t\t}\n\t\t// Return stable reference if output unchanged — allows doRender()\n\t\t// to skip ALL post-processing (isImageLine, applyLineResets, diffs)\n\t\tconst prev = this._prevRender;\n\t\tif (prev && prev.length === lines.length) {\n\t\t\tlet same = true;\n\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\tif (lines[i] !== prev[i]) { same = false; break; }\n\t\t\t}\n\t\t\tif (same) return prev;\n\t\t}\n\t\tthis._prevRender = lines;\n\t\treturn lines;\n\t}\n}\n\n/**\n * TUI - Main class for managing terminal UI with differential rendering\n */\nexport class TUI extends Container {\n\tpublic terminal: Terminal;\n\tprivate previousLines: string[] = [];\n\tprivate previousWidth = 0;\n\tprivate previousHeight = 0;\n\tprivate focusedComponent: Component | null = null;\n\tprivate inputListeners = new Set<InputListener>();\n\n\t/** Global callback for debug key (Shift+Ctrl+D). Called before input is forwarded to focused component. */\n\tpublic onDebug?: () => void;\n\tprivate renderRequested = false;\n\tprivate cursorRow = 0; // Logical cursor row (end of rendered content)\n\tprivate hardwareCursorRow = 0; // Actual terminal cursor row (may differ due to IME positioning)\n\tprivate inputBuffer = \"\"; // Buffer for parsing terminal responses\n\tprivate cellSizeQueryPending = false;\n\tprivate showHardwareCursor = process.env.PI_HARDWARE_CURSOR === \"1\" || process.env.TERM_PROGRAM === \"WarpTerminal\";\n\tprivate clearOnShrink = process.env.PI_CLEAR_ON_SHRINK === \"1\"; // Clear empty rows when content shrinks (default: off)\n\tprivate maxLinesRendered = 0; // Track terminal's working area (max lines ever rendered)\n\tprivate previousViewportTop = 0; // Track previous viewport top for resize-aware cursor moves\n\tprivate fullRedrawCount = 0;\n\tprivate stopped = false;\n\tprivate _lastRenderedComponents: string[] | null = null;\n\n\t// Overlay stack for modal components rendered on top of base content\n\tprivate focusOrderCounter = 0;\n\tprivate overlayStack: {\n\t\tcomponent: Component;\n\t\toptions?: OverlayOptions;\n\t\tpreFocus: Component | null;\n\t\thidden: boolean;\n\t\tfocusOrder: number;\n\t}[] = [];\n\n\tconstructor(terminal: Terminal, showHardwareCursor?: boolean) {\n\t\tsuper();\n\t\tthis.terminal = terminal;\n\t\tif (showHardwareCursor !== undefined) {\n\t\t\tthis.showHardwareCursor = showHardwareCursor;\n\t\t}\n\t}\n\n\tget fullRedraws(): number {\n\t\treturn this.fullRedrawCount;\n\t}\n\n\tgetShowHardwareCursor(): boolean {\n\t\treturn this.showHardwareCursor;\n\t}\n\n\tsetShowHardwareCursor(enabled: boolean): void {\n\t\tif (this.showHardwareCursor === enabled) return;\n\t\tthis.showHardwareCursor = enabled;\n\t\tif (!enabled) {\n\t\t\tthis.terminal.hideCursor();\n\t\t}\n\t\tthis.requestRender();\n\t}\n\n\tgetClearOnShrink(): boolean {\n\t\treturn this.clearOnShrink;\n\t}\n\n\t/**\n\t * Set whether to trigger full re-render when content shrinks.\n\t * When true (default), empty rows are cleared when content shrinks.\n\t * When false, empty rows remain (reduces redraws on slower terminals).\n\t */\n\tsetClearOnShrink(enabled: boolean): void {\n\t\tthis.clearOnShrink = enabled;\n\t}\n\n\tsetFocus(component: Component | null): void {\n\t\t// Clear focused flag on old component\n\t\tif (isFocusable(this.focusedComponent)) {\n\t\t\tthis.focusedComponent.focused = false;\n\t\t}\n\n\t\tthis.focusedComponent = component;\n\n\t\t// Set focused flag on new component\n\t\tif (isFocusable(component)) {\n\t\t\tcomponent.focused = true;\n\t\t}\n\t}\n\n\t/**\n\t * Show an overlay component with configurable positioning and sizing.\n\t * Returns a handle to control the overlay's visibility.\n\t */\n\tshowOverlay(component: Component, options?: OverlayOptions): OverlayHandle {\n\t\tconst entry = {\n\t\t\tcomponent,\n\t\t\toptions,\n\t\t\tpreFocus: this.focusedComponent,\n\t\t\thidden: false,\n\t\t\tfocusOrder: ++this.focusOrderCounter,\n\t\t};\n\t\tthis.overlayStack.push(entry);\n\t\t// Only focus if overlay is actually visible\n\t\tif (!options?.nonCapturing && this.isOverlayVisible(entry)) {\n\t\t\tthis.setFocus(component);\n\t\t}\n\t\tthis.terminal.hideCursor();\n\t\tthis.requestRender();\n\n\t\t// Return handle for controlling this overlay\n\t\treturn {\n\t\t\thide: () => {\n\t\t\t\tconst index = this.overlayStack.indexOf(entry);\n\t\t\t\tif (index !== -1) {\n\t\t\t\t\tthis.overlayStack.splice(index, 1);\n\t\t\t\t\t// Restore focus if this overlay had focus\n\t\t\t\t\tif (this.focusedComponent === component) {\n\t\t\t\t\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\t\t\t\t\tthis.setFocus(topVisible?.component ?? entry.preFocus);\n\t\t\t\t\t}\n\t\t\t\t\tif (this.overlayStack.length === 0) this.terminal.hideCursor();\n\t\t\t\t\tthis.requestRender();\n\t\t\t\t}\n\t\t\t},\n\t\t\tsetHidden: (hidden: boolean) => {\n\t\t\t\tif (entry.hidden === hidden) return;\n\t\t\t\tentry.hidden = hidden;\n\t\t\t\t// Update focus when hiding/showing\n\t\t\t\tif (hidden) {\n\t\t\t\t\t// If this overlay had focus, move focus to next visible or preFocus\n\t\t\t\t\tif (this.focusedComponent === component) {\n\t\t\t\t\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\t\t\t\t\tthis.setFocus(topVisible?.component ?? entry.preFocus);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Restore focus to this overlay when showing (if it's actually visible)\n\t\t\t\t\tif (!options?.nonCapturing && this.isOverlayVisible(entry)) {\n\t\t\t\t\t\tentry.focusOrder = ++this.focusOrderCounter;\n\t\t\t\t\t\tthis.setFocus(component);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.requestRender();\n\t\t\t},\n\t\t\tisHidden: () => entry.hidden,\n\t\t\tfocus: () => {\n\t\t\t\tif (!this.overlayStack.includes(entry) || !this.isOverlayVisible(entry)) return;\n\t\t\t\tif (this.focusedComponent !== component) {\n\t\t\t\t\tthis.setFocus(component);\n\t\t\t\t}\n\t\t\t\tentry.focusOrder = ++this.focusOrderCounter;\n\t\t\t\tthis.requestRender();\n\t\t\t},\n\t\t\tunfocus: () => {\n\t\t\t\tif (this.focusedComponent !== component) return;\n\t\t\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\t\t\tthis.setFocus(topVisible && topVisible !== entry ? topVisible.component : entry.preFocus);\n\t\t\t\tthis.requestRender();\n\t\t\t},\n\t\t\tisFocused: () => this.focusedComponent === component,\n\t\t};\n\t}\n\n\t/** Hide the topmost overlay and restore previous focus. */\n\thideOverlay(): void {\n\t\tconst overlay = this.overlayStack.pop();\n\t\tif (!overlay) return;\n\t\tif (this.focusedComponent === overlay.component) {\n\t\t\t// Find topmost visible overlay, or fall back to preFocus\n\t\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\t\tthis.setFocus(topVisible?.component ?? overlay.preFocus);\n\t\t}\n\t\tif (this.overlayStack.length === 0) this.terminal.hideCursor();\n\t\tthis.requestRender();\n\t}\n\n\t/** Check if there are any visible overlays */\n\thasOverlay(): boolean {\n\t\treturn this.overlayStack.some((o) => this.isOverlayVisible(o));\n\t}\n\n\t/** Check if an overlay entry is currently visible */\n\tprivate isOverlayVisible(entry: (typeof this.overlayStack)[number]): boolean {\n\t\treturn isOverlayEntryVisible(entry, this.terminal.columns, this.terminal.rows);\n\t}\n\n\t/** Find the topmost visible capturing overlay, if any */\n\tprivate getTopmostVisibleOverlay(): (typeof this.overlayStack)[number] | undefined {\n\t\tfor (let i = this.overlayStack.length - 1; i >= 0; i--) {\n\t\t\tif (this.overlayStack[i].options?.nonCapturing) continue;\n\t\t\tif (this.isOverlayVisible(this.overlayStack[i])) {\n\t\t\t\treturn this.overlayStack[i];\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tfor (const overlay of this.overlayStack) overlay.component.invalidate?.();\n\t}\n\n\tstart(): void {\n\t\tthis.stopped = false;\n\t\t// Non-TTY stdout (pipe) — skip TUI entirely to avoid burning CPU.\n\t\t// RPC bridge processes have piped stdio; rendering ANSI escape codes\n\t\t// to a pipe is pure waste and causes a runaway render loop. (issue #3095)\n\t\tif (!this.terminal.isTTY) {\n\t\t\treturn;\n\t\t}\n\t\tthis.terminal.start(\n\t\t\t(data) => this.handleInput(data),\n\t\t\t() => this.requestRender(),\n\t\t);\n\t\tthis.terminal.hideCursor();\n\t\tthis.queryCellSize();\n\t\tthis.requestRender();\n\t}\n\n\taddInputListener(listener: InputListener): () => void {\n\t\tthis.inputListeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.inputListeners.delete(listener);\n\t\t};\n\t}\n\n\tremoveInputListener(listener: InputListener): void {\n\t\tthis.inputListeners.delete(listener);\n\t}\n\n\tprivate queryCellSize(): void {\n\t\t// Only query if terminal supports images (cell size is only used for image rendering)\n\t\tif (!getCapabilities().images) {\n\t\t\treturn;\n\t\t}\n\t\t// Query terminal for cell size in pixels: CSI 16 t\n\t\t// Response format: CSI 6 ; height ; width t\n\t\tthis.cellSizeQueryPending = true;\n\t\tthis.terminal.write(\"\\x1b[16t\");\n\t}\n\n\tstop(): void {\n\t\tthis.stopped = true;\n\n\t\t// Dispose all overlays to stop any running timers\n\t\tfor (const entry of this.overlayStack) {\n\t\t\tif (\"dispose\" in entry.component && typeof (entry.component as any).dispose === \"function\") {\n\t\t\t\t(entry.component as any).dispose();\n\t\t\t}\n\t\t}\n\t\tthis.overlayStack = [];\n\n\t\t// Move cursor to the end of the content to prevent overwriting/artifacts on exit\n\t\tif (this.previousLines.length > 0) {\n\t\t\tconst targetRow = this.previousLines.length; // Line after the last content\n\t\t\tconst lineDiff = targetRow - this.hardwareCursorRow;\n\t\t\tif (lineDiff > 0) {\n\t\t\t\tthis.terminal.write(`\\x1b[${lineDiff}B`);\n\t\t\t} else if (lineDiff < 0) {\n\t\t\t\tthis.terminal.write(`\\x1b[${-lineDiff}A`);\n\t\t\t}\n\t\t\tthis.terminal.write(\"\\r\\n\");\n\t\t}\n\n\t\tthis.terminal.showCursor();\n\t\tthis.terminal.stop();\n\t}\n\n\trequestRender(force = false): void {\n\t\t// Skip rendering on non-TTY stdout to prevent CPU burn (issue #3095)\n\t\tif (!this.terminal.isTTY) return;\n\t\tif (force) {\n\t\t\tthis.previousLines = [];\n\t\t\tthis.previousWidth = -1; // -1 triggers widthChanged, forcing a full clear\n\t\t\tthis.previousHeight = -1; // -1 triggers heightChanged, forcing a full clear\n\t\t\tthis.cursorRow = 0;\n\t\t\tthis.hardwareCursorRow = 0;\n\t\t\tthis.maxLinesRendered = 0;\n\t\t\tthis.previousViewportTop = 0;\n\t\t}\n\t\tif (this.renderRequested) return;\n\t\tthis.renderRequested = true;\n\t\tprocess.nextTick(() => {\n\t\t\tthis.renderRequested = false;\n\t\t\tthis.doRender();\n\t\t});\n\t}\n\n\tprivate handleInput(data: string): void {\n\t\tif (this.inputListeners.size > 0) {\n\t\t\tlet current = data;\n\t\t\tfor (const listener of this.inputListeners) {\n\t\t\t\tconst result = listener(current);\n\t\t\t\tif (result?.consume) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (result?.data !== undefined) {\n\t\t\t\t\tcurrent = result.data;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (current.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdata = current;\n\t\t}\n\n\t\t// If we're waiting for cell size response, buffer input and parse\n\t\tif (this.cellSizeQueryPending) {\n\t\t\tthis.inputBuffer += data;\n\t\t\tconst filtered = this.parseCellSizeResponse();\n\t\t\tif (filtered.length === 0) return;\n\t\t\tdata = filtered;\n\t\t}\n\n\t\t// Global debug key handler (Shift+Ctrl+D)\n\t\tif (matchesKey(data, \"shift+ctrl+d\") && this.onDebug) {\n\t\t\tthis.onDebug();\n\t\t\treturn;\n\t\t}\n\n\t\t// If focused component is an overlay, verify it's still visible\n\t\t// (visibility can change due to terminal resize or visible() callback)\n\t\tconst focusedOverlay = this.overlayStack.find((o) => o.component === this.focusedComponent);\n\t\tif (focusedOverlay && !this.isOverlayVisible(focusedOverlay)) {\n\t\t\t// Focused overlay is no longer visible, redirect to topmost visible overlay\n\t\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\t\tif (topVisible) {\n\t\t\t\tthis.setFocus(topVisible.component);\n\t\t\t} else {\n\t\t\t\t// No visible overlays, restore to preFocus\n\t\t\t\tthis.setFocus(focusedOverlay.preFocus);\n\t\t\t}\n\t\t}\n\n\t\t// Pass input to focused component (including Ctrl+C)\n\t\t// The focused component can decide how to handle Ctrl+C\n\t\tif (this.focusedComponent?.handleInput) {\n\t\t\t// Filter out key release events unless component opts in\n\t\t\tif (isKeyRelease(data) && !this.focusedComponent.wantsKeyRelease) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.focusedComponent.handleInput(data);\n\t\t\tthis.requestRender();\n\t\t}\n\t}\n\n\tprivate parseCellSizeResponse(): string {\n\t\t// Response format: ESC [ 6 ; height ; width t\n\t\t// Match the response pattern\n\t\tconst responsePattern = /\\x1b\\[6;(\\d+);(\\d+)t/;\n\t\tconst match = this.inputBuffer.match(responsePattern);\n\n\t\tif (match) {\n\t\t\tconst heightPx = parseInt(match[1], 10);\n\t\t\tconst widthPx = parseInt(match[2], 10);\n\n\t\t\tif (heightPx > 0 && widthPx > 0) {\n\t\t\t\tsetCellDimensions({ widthPx, heightPx });\n\t\t\t\t// Invalidate all components so images re-render with correct dimensions\n\t\t\t\tthis.invalidate();\n\t\t\t\tthis.requestRender();\n\t\t\t}\n\n\t\t\t// Remove the response from buffer\n\t\t\tthis.inputBuffer = this.inputBuffer.replace(responsePattern, \"\");\n\t\t\tthis.cellSizeQueryPending = false;\n\t\t}\n\n\t\t// Check if we have a partial cell size response starting (wait for more data)\n\t\t// Patterns that could be incomplete cell size response: \\x1b, \\x1b[, \\x1b[6, \\x1b[6;...(no t yet)\n\t\tconst partialCellSizePattern = /\\x1b(\\[6?;?[\\d;]*)?$/;\n\t\tif (partialCellSizePattern.test(this.inputBuffer)) {\n\t\t\t// Check if it's actually a complete different escape sequence (ends with a letter)\n\t\t\t// Cell size response ends with 't', Kitty keyboard ends with 'u', arrows end with A-D, etc.\n\t\t\tconst lastChar = this.inputBuffer[this.inputBuffer.length - 1];\n\t\t\tif (!/[a-zA-Z~]/.test(lastChar)) {\n\t\t\t\t// Doesn't end with a terminator, might be incomplete - wait for more\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t}\n\n\t\t// No cell size response found, return buffered data as user input\n\t\tconst result = this.inputBuffer;\n\t\tthis.inputBuffer = \"\";\n\t\tthis.cellSizeQueryPending = false; // Give up waiting\n\t\treturn result;\n\t}\n\n\tprivate doRender(): void {\n\t\tif (this.stopped) return;\n\t\tconst width = this.terminal.columns;\n\t\tconst height = this.terminal.rows;\n\t\tlet viewportTop = Math.max(0, this.maxLinesRendered - height);\n\t\tlet prevViewportTop = this.previousViewportTop;\n\t\tlet hardwareCursorRow = this.hardwareCursorRow;\n\t\tconst computeLineDiff = (targetRow: number): number => {\n\t\t\tconst currentScreenRow = hardwareCursorRow - prevViewportTop;\n\t\t\tconst targetScreenRow = targetRow - viewportTop;\n\t\t\treturn targetScreenRow - currentScreenRow;\n\t\t};\n\n\t\t// Render all components to get new lines\n\t\tlet newLines = this.render(width);\n\n\t\t// Skip ALL post-processing if component output is unchanged.\n\t\t// Container.render() returns the same array reference when stable.\n\t\tif (newLines === this._lastRenderedComponents && this.overlayStack.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tthis._lastRenderedComponents = newLines;\n\n\t\t// Composite overlays into the rendered lines (before differential compare)\n\t\tif (this.overlayStack.length > 0) {\n\t\t\tnewLines = compositeOverlays(newLines, this.overlayStack, width, height, this.maxLinesRendered);\n\t\t}\n\n\t\t// Extract cursor position before applying line resets (marker must be found first)\n\t\tconst cursorPos = extractCursorPosition(newLines, height);\n\n\t\tnewLines = applyLineResets(newLines);\n\n\t\t// Width or height changed - need full re-render\n\t\tconst widthChanged = this.previousWidth !== 0 && this.previousWidth !== width;\n\t\tconst heightChanged = this.previousHeight !== 0 && this.previousHeight !== height;\n\n\t\t// Helper to clear scrollback and viewport and render all new lines\n\t\tconst fullRender = (clear: boolean): void => {\n\t\t\tthis.fullRedrawCount += 1;\n\t\t\tlet buffer = \"\\x1b[?2026h\"; // Begin synchronized output\n\t\t\tif (clear) buffer += \"\\x1b[2J\\x1b[H\"; // Clear screen and home (no scrollback clear — preserves view position)\n\t\t\tfor (let i = 0; i < newLines.length; i++) {\n\t\t\t\tif (i > 0) buffer += \"\\r\\n\";\n\t\t\t\tlet line = newLines[i];\n\t\t\t\tif (!isImageLine(line) && visibleWidth(line) > width) {\n\t\t\t\t\tline = truncateToWidth(line, width);\n\t\t\t\t}\n\t\t\t\tbuffer += line;\n\t\t\t}\n\t\t\tbuffer += \"\\x1b[?2026l\"; // End synchronized output\n\t\t\tthis.terminal.write(buffer);\n\t\t\tthis.cursorRow = Math.max(0, newLines.length - 1);\n\t\t\tthis.hardwareCursorRow = this.cursorRow;\n\t\t\t// Reset max lines when clearing, otherwise track growth\n\t\t\tif (clear) {\n\t\t\t\tthis.maxLinesRendered = newLines.length;\n\t\t\t} else {\n\t\t\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, newLines.length);\n\t\t\t}\n\t\t\tthis.previousViewportTop = Math.max(0, this.maxLinesRendered - height);\n\t\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\t\t\tthis.previousLines = newLines;\n\t\t\tthis.previousWidth = width;\n\t\t\tthis.previousHeight = height;\n\t\t};\n\n\t\tconst debugRedraw = process.env.PI_DEBUG_REDRAW === \"1\";\n\t\tconst logRedraw = (reason: string): void => {\n\t\t\tif (!debugRedraw) return;\n\t\t\tconst logPath = path.join(os.homedir(), \".pi\", \"agent\", \"pi-debug.log\");\n\t\t\tconst msg = `[${new Date().toISOString()}] fullRender: ${reason} (prev=${this.previousLines.length}, new=${newLines.length}, height=${height})\\n`;\n\t\t\tfs.appendFileSync(logPath, msg);\n\t\t};\n\n\t\t// First render - just output everything without clearing (assumes clean screen)\n\t\tif (this.previousLines.length === 0 && !widthChanged && !heightChanged) {\n\t\t\tlogRedraw(\"first render\");\n\t\t\tfullRender(false);\n\t\t\treturn;\n\t\t}\n\n\t\t// Width or height changed - full re-render\n\t\tif (widthChanged || heightChanged) {\n\t\t\tlogRedraw(`terminal size changed (${this.previousWidth}x${this.previousHeight} -> ${width}x${height})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Content shrunk below the working area and no overlays - re-render to clear empty rows\n\t\t// (overlays need the padding, so only do this when no overlays are active)\n\t\t// Configurable via setClearOnShrink() or PI_CLEAR_ON_SHRINK=0 env var\n\t\tif (this.clearOnShrink && newLines.length < this.maxLinesRendered && this.overlayStack.length === 0) {\n\t\t\tlogRedraw(`clearOnShrink (maxLinesRendered=${this.maxLinesRendered})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Find first and last changed lines\n\t\tlet firstChanged = -1;\n\t\tlet lastChanged = -1;\n\t\tconst maxLines = Math.max(newLines.length, this.previousLines.length);\n\t\tfor (let i = 0; i < maxLines; i++) {\n\t\t\tconst oldLine = i < this.previousLines.length ? this.previousLines[i] : \"\";\n\t\t\tconst newLine = i < newLines.length ? newLines[i] : \"\";\n\n\t\t\tif (oldLine !== newLine) {\n\t\t\t\tif (firstChanged === -1) {\n\t\t\t\t\tfirstChanged = i;\n\t\t\t\t}\n\t\t\t\tlastChanged = i;\n\t\t\t}\n\t\t}\n\t\tconst appendedLines = newLines.length > this.previousLines.length;\n\t\tif (appendedLines) {\n\t\t\tif (firstChanged === -1) {\n\t\t\t\tfirstChanged = this.previousLines.length;\n\t\t\t}\n\t\t\tlastChanged = newLines.length - 1;\n\t\t}\n\t\tconst appendStart = appendedLines && firstChanged === this.previousLines.length && firstChanged > 0;\n\n\t\t// No changes - but still need to update hardware cursor position if it moved\n\t\tif (firstChanged === -1) {\n\t\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\t\t\tthis.previousViewportTop = Math.max(0, this.maxLinesRendered - height);\n\t\t\tthis.previousHeight = height;\n\t\t\treturn;\n\t\t}\n\n\t\t// All changes are in deleted lines (nothing to render, just clear)\n\t\tif (firstChanged >= newLines.length) {\n\t\t\tif (this.previousLines.length > newLines.length) {\n\t\t\t\tlet buffer = \"\\x1b[?2026h\";\n\t\t\t\t// Move to end of new content (clamp to 0 for empty content)\n\t\t\t\tconst targetRow = Math.max(0, newLines.length - 1);\n\t\t\t\tconst lineDiff = computeLineDiff(targetRow);\n\t\t\t\tif (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n\t\t\t\telse if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n\t\t\t\tbuffer += \"\\r\";\n\t\t\t\t// Clear extra lines without scrolling\n\t\t\t\tconst extraLines = this.previousLines.length - newLines.length;\n\t\t\t\tif (extraLines > height) {\n\t\t\t\t\tlogRedraw(`extraLines > height (${extraLines} > ${height})`);\n\t\t\t\t\tfullRender(true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (extraLines > 0) {\n\t\t\t\t\tbuffer += \"\\x1b[1B\";\n\t\t\t\t}\n\t\t\t\tfor (let i = 0; i < extraLines; i++) {\n\t\t\t\t\tbuffer += \"\\r\\x1b[2K\";\n\t\t\t\t\tif (i < extraLines - 1) buffer += \"\\x1b[1B\";\n\t\t\t\t}\n\t\t\t\tif (extraLines > 0) {\n\t\t\t\t\tbuffer += `\\x1b[${extraLines}A`;\n\t\t\t\t}\n\t\t\t\tbuffer += \"\\x1b[?2026l\";\n\t\t\t\tthis.terminal.write(buffer);\n\t\t\t\tthis.cursorRow = targetRow;\n\t\t\t\tthis.hardwareCursorRow = targetRow;\n\t\t\t}\n\t\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\t\t\tthis.previousLines = newLines;\n\t\t\tthis.previousWidth = width;\n\t\t\tthis.previousHeight = height;\n\t\t\tthis.previousViewportTop = Math.max(0, this.maxLinesRendered - height);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if firstChanged is above what was previously visible\n\t\t// Use previousLines.length (not maxLinesRendered) to avoid false positives after content shrinks\n\t\tconst previousContentViewportTop = Math.max(0, this.previousLines.length - height);\n\t\tif (firstChanged < previousContentViewportTop) {\n\t\t\t// First change is above previous viewport - need full re-render\n\t\t\tlogRedraw(`firstChanged < viewportTop (${firstChanged} < ${previousContentViewportTop})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Render from first changed line to end\n\t\t// Build buffer with all updates wrapped in synchronized output\n\t\tlet buffer = \"\\x1b[?2026h\"; // Begin synchronized output\n\t\tconst prevViewportBottom = prevViewportTop + height - 1;\n\t\tconst moveTargetRow = appendStart ? firstChanged - 1 : firstChanged;\n\t\tif (moveTargetRow > prevViewportBottom) {\n\t\t\tconst currentScreenRow = Math.max(0, Math.min(height - 1, hardwareCursorRow - prevViewportTop));\n\t\t\tconst moveToBottom = height - 1 - currentScreenRow;\n\t\t\tif (moveToBottom > 0) {\n\t\t\t\tbuffer += `\\x1b[${moveToBottom}B`;\n\t\t\t}\n\t\t\tconst scroll = moveTargetRow - prevViewportBottom;\n\t\t\tbuffer += \"\\r\\n\".repeat(scroll);\n\t\t\tprevViewportTop += scroll;\n\t\t\tviewportTop += scroll;\n\t\t\thardwareCursorRow = moveTargetRow;\n\t\t}\n\n\t\t// Move cursor to first changed line (use hardwareCursorRow for actual position)\n\t\tconst lineDiff = computeLineDiff(moveTargetRow);\n\t\tif (lineDiff > 0) {\n\t\t\tbuffer += `\\x1b[${lineDiff}B`; // Move down\n\t\t} else if (lineDiff < 0) {\n\t\t\tbuffer += `\\x1b[${-lineDiff}A`; // Move up\n\t\t}\n\n\t\tbuffer += appendStart ? \"\\r\\n\" : \"\\r\"; // Move to column 0\n\n\t\t// Only render changed lines (firstChanged to lastChanged), not all lines to end\n\t\t// This reduces flicker when only a single line changes (e.g., spinner animation)\n\t\tconst renderEnd = Math.min(lastChanged, newLines.length - 1);\n\t\tfor (let i = firstChanged; i <= renderEnd; i++) {\n\t\t\tif (i > firstChanged) buffer += \"\\r\\n\";\n\t\t\tbuffer += \"\\x1b[2K\"; // Clear current line\n\t\t\tlet line = newLines[i];\n\t\t\tconst isImage = isImageLine(line);\n\t\t\tif (!isImage && visibleWidth(line) > width) {\n\t\t\t\tline = truncateToWidth(line, width);\n\t\t\t}\n\t\t\tbuffer += line;\n\t\t}\n\n\t\t// Track where cursor ended up after rendering\n\t\tlet finalCursorRow = renderEnd;\n\n\t\t// If we had more lines before, clear them and move cursor back\n\t\tif (this.previousLines.length > newLines.length) {\n\t\t\t// Move to end of new content first if we stopped before it\n\t\t\tif (renderEnd < newLines.length - 1) {\n\t\t\t\tconst moveDown = newLines.length - 1 - renderEnd;\n\t\t\t\tbuffer += `\\x1b[${moveDown}B`;\n\t\t\t\tfinalCursorRow = newLines.length - 1;\n\t\t\t}\n\t\t\tconst extraLines = this.previousLines.length - newLines.length;\n\t\t\tfor (let i = newLines.length; i < this.previousLines.length; i++) {\n\t\t\t\tbuffer += \"\\r\\n\\x1b[2K\";\n\t\t\t}\n\t\t\t// Move cursor back to end of new content\n\t\t\tbuffer += `\\x1b[${extraLines}A`;\n\t\t}\n\n\t\tbuffer += \"\\x1b[?2026l\"; // End synchronized output\n\n\t\tif (process.env.PI_TUI_DEBUG === \"1\") {\n\t\t\tconst debugDir = path.join(os.tmpdir(), \"tui\");\n\t\t\tfs.mkdirSync(debugDir, { recursive: true });\n\t\t\tconst debugPath = path.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);\n\t\t\tconst debugData = [\n\t\t\t\t`firstChanged: ${firstChanged}`,\n\t\t\t\t`viewportTop: ${viewportTop}`,\n\t\t\t\t`cursorRow: ${this.cursorRow}`,\n\t\t\t\t`height: ${height}`,\n\t\t\t\t`lineDiff: ${lineDiff}`,\n\t\t\t\t`hardwareCursorRow: ${hardwareCursorRow}`,\n\t\t\t\t`renderEnd: ${renderEnd}`,\n\t\t\t\t`finalCursorRow: ${finalCursorRow}`,\n\t\t\t\t`cursorPos: ${JSON.stringify(cursorPos)}`,\n\t\t\t\t`newLines.length: ${newLines.length}`,\n\t\t\t\t`previousLines.length: ${this.previousLines.length}`,\n\t\t\t\t\"\",\n\t\t\t\t\"=== newLines ===\",\n\t\t\t\tJSON.stringify(newLines, null, 2),\n\t\t\t\t\"\",\n\t\t\t\t\"=== previousLines ===\",\n\t\t\t\tJSON.stringify(this.previousLines, null, 2),\n\t\t\t\t\"\",\n\t\t\t\t\"=== buffer ===\",\n\t\t\t\tJSON.stringify(buffer),\n\t\t\t].join(\"\\n\");\n\t\t\tfs.writeFileSync(debugPath, debugData);\n\t\t}\n\n\t\t// Write entire buffer at once\n\t\tthis.terminal.write(buffer);\n\n\t\t// Track cursor position for next render\n\t\t// cursorRow tracks end of content (for viewport calculation)\n\t\t// hardwareCursorRow tracks actual terminal cursor position (for movement)\n\t\tthis.cursorRow = Math.max(0, newLines.length - 1);\n\t\tthis.hardwareCursorRow = finalCursorRow;\n\t\t// Track terminal's working area (grows but doesn't shrink unless cleared)\n\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, newLines.length);\n\t\tthis.previousViewportTop = Math.max(0, this.maxLinesRendered - height);\n\n\t\t// Position hardware cursor for IME\n\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\n\t\tthis.previousLines = newLines;\n\t\tthis.previousWidth = width;\n\t\tthis.previousHeight = height;\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: { row: number; col: number } | 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.showHardwareCursor) {\n\t\t\tthis.terminal.showCursor();\n\t\t} else {\n\t\t\tthis.terminal.hideCursor();\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,65 @@
1
+ // pi-tui — Overlay Layout Tests (backdrop dimming)
2
+
3
+ import { describe, it } from "node:test";
4
+ import assert from "node:assert/strict";
5
+ import { compositeOverlays, type OverlayEntry } from "../overlay-layout.js";
6
+
7
+ function makeEntry(
8
+ lines: string[],
9
+ options?: OverlayEntry["options"],
10
+ ): OverlayEntry {
11
+ return {
12
+ component: { render: () => lines },
13
+ options,
14
+ hidden: false,
15
+ focusOrder: 1,
16
+ };
17
+ }
18
+
19
+ describe("compositeOverlays — backdrop", () => {
20
+ it("dims base lines when backdrop is true", () => {
21
+ const base = ["hello world", "second line"];
22
+ const overlay = makeEntry(["OVERLAY"], {
23
+ width: 7,
24
+ anchor: "top-left",
25
+ backdrop: true,
26
+ });
27
+
28
+ const result = compositeOverlays(base, [overlay], 20, 20, 2);
29
+
30
+ // All base lines in viewport should contain dim escape (\x1b[2m)
31
+ // The overlay line itself is composited on top, but underlying lines get dimmed
32
+ const dimmedLine = result.find((l) => l.includes("second line"));
33
+ assert.ok(dimmedLine, "should have a line containing 'second line'");
34
+ assert.ok(dimmedLine.includes("\x1b[2m"), "base line should be dimmed");
35
+ });
36
+
37
+ it("does not dim when backdrop is false/absent", () => {
38
+ const base = ["hello world", "second line"];
39
+ const overlay = makeEntry(["OVERLAY"], {
40
+ width: 7,
41
+ anchor: "top-left",
42
+ });
43
+
44
+ const result = compositeOverlays(base, [overlay], 20, 20, 2);
45
+
46
+ // Lines not covered by overlay should remain undimmed
47
+ const secondLine = result.find((l) => l.includes("second line"));
48
+ assert.ok(secondLine, "should have a line containing 'second line'");
49
+ assert.ok(!secondLine.includes("\x1b[2m"), "base line should not be dimmed");
50
+ });
51
+
52
+ it("overlay content renders on top of dimmed background", () => {
53
+ const base = ["aaaaaaaaaa"];
54
+ const overlay = makeEntry(["XX"], {
55
+ width: 2,
56
+ anchor: "top-left",
57
+ backdrop: true,
58
+ });
59
+
60
+ const result = compositeOverlays(base, [overlay], 10, 10, 1);
61
+
62
+ // The first line should contain the overlay text
63
+ assert.ok(result[0].includes("XX"), "overlay text should be composited");
64
+ });
65
+ });
@@ -2,13 +2,16 @@ import type { TUI } from "../tui.js";
2
2
  import { Text } from "./text.js";
3
3
 
4
4
  /**
5
- * Loader component that updates every 80ms with spinning animation
5
+ * Loader component that updates every 80ms with spinning animation.
6
+ * Frame rotation is isolated from message text to avoid invalidating
7
+ * Text's render cache (wrapTextWithAnsi, visibleWidth) on every tick.
6
8
  */
7
9
  export class Loader extends Text {
8
10
  private frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
9
11
  private currentFrame = 0;
10
12
  private intervalId: NodeJS.Timeout | null = null;
11
13
  private ui: TUI | null = null;
14
+ private _lastMessage: string = "";
12
15
 
13
16
  constructor(
14
17
  ui: TUI,
@@ -22,18 +25,38 @@ export class Loader extends Text {
22
25
  }
23
26
 
24
27
  render(width: number): string[] {
25
- return ["", ...super.render(width)];
28
+ // Only update Text content when message actually changes —
29
+ // frame rotation is prepended below without touching the cache
30
+ if (this.message !== this._lastMessage) {
31
+ this.setText(this.messageColorFn(this.message));
32
+ this._lastMessage = this.message;
33
+ }
34
+ const messageLines = super.render(width);
35
+ // Shallow copy so we don't mutate cachedLines from Text
36
+ const result = ["", ...messageLines];
37
+ // Prepend spinner frame to first content line
38
+ if (result.length > 1) {
39
+ const frame = this.frames[this.currentFrame];
40
+ result[1] = this.spinnerColorFn(frame) + " " + result[1];
41
+ }
42
+ return result;
26
43
  }
27
44
 
28
45
  start() {
29
46
  if (this.intervalId) {
30
47
  clearInterval(this.intervalId);
31
48
  }
32
- this.updateDisplay();
49
+ this.currentFrame = 0;
33
50
  this.intervalId = setInterval(() => {
34
51
  this.currentFrame = (this.currentFrame + 1) % this.frames.length;
35
- this.updateDisplay();
52
+ if (this.ui) {
53
+ this.ui.requestRender();
54
+ }
36
55
  }, 80);
56
+ // Trigger initial render
57
+ if (this.ui) {
58
+ this.ui.requestRender();
59
+ }
37
60
  }
38
61
 
39
62
  stop() {
@@ -50,12 +73,6 @@ export class Loader extends Text {
50
73
 
51
74
  setMessage(message: string) {
52
75
  this.message = message;
53
- this.updateDisplay();
54
- }
55
-
56
- private updateDisplay() {
57
- const frame = this.frames[this.currentFrame];
58
- this.setText(`${this.spinnerColorFn(frame)} ${this.messageColorFn(this.message)}`);
59
76
  if (this.ui) {
60
77
  this.ui.requestRender();
61
78
  }
@@ -23,6 +23,7 @@ export class Text implements Component {
23
23
  }
24
24
 
25
25
  setText(text: string): void {
26
+ if (this.text === text) return;
26
27
  this.text = text;
27
28
  this.cachedText = undefined;
28
29
  this.cachedWidth = undefined;
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import type { OverlayAnchor, OverlayOptions, SizeValue } from "./tui.js";
9
- import { extractSegments, sliceByColumn, sliceWithWidth, truncateToWidth, visibleWidth } from "./utils.js";
9
+ import { applyBackgroundToLine, extractSegments, sliceByColumn, sliceWithWidth, truncateToWidth, visibleWidth } from "./utils.js";
10
10
  import { isImageLine } from "./terminal-image.js";
11
11
  import { CURSOR_MARKER } from "./tui.js";
12
12
 
@@ -324,6 +324,17 @@ export function compositeOverlays(
324
324
 
325
325
  const viewportStart = Math.max(0, workingHeight - termHeight);
326
326
 
327
+ // Apply backdrop dimming if any visible overlay requests it
328
+ const hasBackdrop = visibleEntries.some((e) => e.options?.backdrop);
329
+ if (hasBackdrop) {
330
+ const dimFn = (text: string) => `\x1b[2m${text}\x1b[22m`;
331
+ for (let i = viewportStart; i < result.length; i++) {
332
+ if (!isImageLine(result[i]) && result[i].length > 0) {
333
+ result[i] = applyBackgroundToLine(result[i], termWidth, dimFn);
334
+ }
335
+ }
336
+ }
337
+
327
338
  // Composite each overlay
328
339
  for (const { overlayLines, row, col, w } of rendered) {
329
340
  for (let i = 0; i < overlayLines.length; i++) {
@@ -141,6 +141,8 @@ export interface OverlayOptions {
141
141
  visible?: (termWidth: number, termHeight: number) => boolean;
142
142
  /** If true, don't capture keyboard focus when shown */
143
143
  nonCapturing?: boolean;
144
+ /** If true, dim the background behind the overlay */
145
+ backdrop?: boolean;
144
146
  }
145
147
 
146
148
  /**
@@ -166,20 +168,33 @@ export interface OverlayHandle {
166
168
  */
167
169
  export class Container implements Component {
168
170
  children: Component[] = [];
171
+ private _prevRender: string[] | null = null;
169
172
 
170
173
  addChild(component: Component): void {
171
174
  this.children.push(component);
175
+ this._prevRender = null;
172
176
  }
173
177
 
174
178
  removeChild(component: Component): void {
175
179
  const index = this.children.indexOf(component);
176
180
  if (index !== -1) {
181
+ const child = this.children[index];
177
182
  this.children.splice(index, 1);
183
+ if ('dispose' in child && typeof (child as any).dispose === 'function') {
184
+ (child as any).dispose();
185
+ }
186
+ this._prevRender = null;
178
187
  }
179
188
  }
180
189
 
181
190
  clear(): void {
191
+ for (const child of this.children) {
192
+ if ('dispose' in child && typeof (child as any).dispose === 'function') {
193
+ (child as any).dispose();
194
+ }
195
+ }
182
196
  this.children = [];
197
+ this._prevRender = null;
183
198
  }
184
199
 
185
200
  invalidate(): void {
@@ -194,6 +209,17 @@ export class Container implements Component {
194
209
  const rendered = child.render(width);
195
210
  for (let i = 0; i < rendered.length; i++) lines.push(rendered[i]);
196
211
  }
212
+ // Return stable reference if output unchanged — allows doRender()
213
+ // to skip ALL post-processing (isImageLine, applyLineResets, diffs)
214
+ const prev = this._prevRender;
215
+ if (prev && prev.length === lines.length) {
216
+ let same = true;
217
+ for (let i = 0; i < lines.length; i++) {
218
+ if (lines[i] !== prev[i]) { same = false; break; }
219
+ }
220
+ if (same) return prev;
221
+ }
222
+ this._prevRender = lines;
197
223
  return lines;
198
224
  }
199
225
  }
@@ -222,6 +248,7 @@ export class TUI extends Container {
222
248
  private previousViewportTop = 0; // Track previous viewport top for resize-aware cursor moves
223
249
  private fullRedrawCount = 0;
224
250
  private stopped = false;
251
+ private _lastRenderedComponents: string[] | null = null;
225
252
 
226
253
  // Overlay stack for modal components rendered on top of base content
227
254
  private focusOrderCounter = 0;
@@ -599,6 +626,13 @@ export class TUI extends Container {
599
626
  // Render all components to get new lines
600
627
  let newLines = this.render(width);
601
628
 
629
+ // Skip ALL post-processing if component output is unchanged.
630
+ // Container.render() returns the same array reference when stable.
631
+ if (newLines === this._lastRenderedComponents && this.overlayStack.length === 0) {
632
+ return;
633
+ }
634
+ this._lastRenderedComponents = newLines;
635
+
602
636
  // Composite overlays into the rendered lines (before differential compare)
603
637
  if (this.overlayStack.length > 0) {
604
638
  newLines = compositeOverlays(newLines, this.overlayStack, width, height, this.maxLinesRendered);
@@ -16,6 +16,7 @@ import {
16
16
  import {
17
17
  processes,
18
18
  pendingAlerts,
19
+ pushAlert,
19
20
  cleanupAll,
20
21
  cleanupSessionProcesses,
21
22
  persistManifest,
@@ -37,19 +38,30 @@ export function registerBgShellLifecycle(pi: ExtensionAPI, state: BgShellSharedS
37
38
  }
38
39
  }
39
40
 
40
- // Clean up on session shutdown
41
- pi.on("session_shutdown", async () => {
42
- cleanupAll();
43
- });
44
-
45
41
  // Register signal handlers to clean up bg processes on unexpected exit (fixes #428)
46
42
  const signalCleanup = () => {
47
43
  cleanupAll();
44
+ // Also kill bash-tool spawned children that bg-shell doesn't track
45
+ try {
46
+ const { listDescendants } = require("@gsd/native") as typeof import("@gsd/native");
47
+ const descendants = listDescendants(process.pid);
48
+ for (const childPid of descendants) {
49
+ try { process.kill(childPid, "SIGKILL"); } catch {}
50
+ }
51
+ } catch {}
48
52
  };
49
53
  process.on("SIGTERM", signalCleanup);
50
54
  process.on("SIGINT", signalCleanup);
51
55
  process.on("beforeExit", signalCleanup);
52
56
 
57
+ // Clean up on session shutdown — remove signal handlers to prevent accumulation
58
+ pi.on("session_shutdown", async () => {
59
+ process.off("SIGTERM", signalCleanup);
60
+ process.off("SIGINT", signalCleanup);
61
+ process.off("beforeExit", signalCleanup);
62
+ cleanupAll();
63
+ });
64
+
53
65
  // ── Compaction Awareness: Survive Context Resets ───────────────
54
66
 
55
67
  /** Build a compact state summary of all alive processes for context re-injection */
@@ -65,7 +77,7 @@ export function registerBgShellLifecycle(pi: ExtensionAPI, state: BgShellSharedS
65
77
  return ` - id:${p.id} "${p.label}" [${p.processType}] status:${p.status} uptime:${formatUptime(Date.now() - p.startedAt)}${portInfo}${urlInfo}${errInfo}${groupInfo}`;
66
78
  }).join("\n");
67
79
 
68
- pendingAlerts.push(
80
+ pushAlert(null,
69
81
  `${reason} ${alive.length} background process(es) are still running:\n${processSummaries}\nUse bg_shell digest/output/kill with these IDs.`
70
82
  );
71
83
  }
@@ -150,7 +162,7 @@ export function registerBgShellLifecycle(pi: ExtensionAPI, state: BgShellSharedS
150
162
  ` - ${s.id}: ${s.label} (pid ${s.pid}, type: ${s.processType}${s.group ? `, group: ${s.group}` : ""})`
151
163
  ).join("\n");
152
164
 
153
- pendingAlerts.push(
165
+ pushAlert(null,
154
166
  `${surviving.length} background process(es) from previous session still running:\n${summary}\n Note: These processes are outside bg_shell's control. Kill them manually if needed.`
155
167
  );
156
168
  }
@@ -33,6 +33,8 @@ export const processes = new Map<string, BgProcess>();
33
33
  /** Pending alerts to inject into the next agent context */
34
34
  export let pendingAlerts: string[] = [];
35
35
 
36
+ const MAX_PENDING_ALERTS = 50;
37
+
36
38
  /** Replace the pendingAlerts array (used by the extension entry point) */
37
39
  export function setPendingAlerts(alerts: string[]): void {
38
40
  pendingAlerts = alerts;
@@ -58,8 +60,12 @@ export function addEvent(bg: BgProcess, event: Omit<ProcessEvent, "timestamp">):
58
60
  }
59
61
  }
60
62
 
61
- export function pushAlert(bg: BgProcess, message: string): void {
62
- pendingAlerts.push(`[bg:${bg.id} ${bg.label}] ${message}`);
63
+ export function pushAlert(bg: BgProcess | null, message: string): void {
64
+ const prefix = bg ? `[bg:${bg.id} ${bg.label}] ` : "";
65
+ pendingAlerts.push(`${prefix}${message}`);
66
+ if (pendingAlerts.length > MAX_PENDING_ALERTS) {
67
+ pendingAlerts.splice(0, pendingAlerts.length - MAX_PENDING_ALERTS);
68
+ }
63
69
  }
64
70
 
65
71
  export function getInfo(p: BgProcess): BgProcessInfo {