lsd-pi 1.1.4 → 1.1.6

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 (175) hide show
  1. package/README.md +2 -1
  2. package/dist/headless-ui.js +2 -0
  3. package/dist/onboarding.js +11 -8
  4. package/dist/resources/extensions/async-jobs/async-bash-tool.js +14 -0
  5. package/dist/resources/extensions/async-jobs/await-tool.js +14 -0
  6. package/dist/resources/extensions/async-jobs/cancel-job-tool.js +7 -0
  7. package/dist/resources/extensions/cache-timer/index.js +5 -0
  8. package/dist/resources/extensions/codex-rotate/IMPLEMENTATION.md +18 -13
  9. package/dist/resources/extensions/codex-rotate/README.md +9 -3
  10. package/dist/resources/extensions/codex-rotate/commands.js +15 -8
  11. package/dist/resources/extensions/codex-rotate/index.js +17 -8
  12. package/dist/resources/extensions/memory/auto-extract.js +196 -80
  13. package/dist/resources/extensions/memory/dream.js +86 -19
  14. package/dist/resources/extensions/shared/rtk.js +89 -87
  15. package/dist/resources/extensions/subagent/index.js +33 -7
  16. package/dist/startup-model-validation.js +12 -2
  17. package/dist/update-check.js +2 -2
  18. package/dist/update-cmd.js +3 -3
  19. package/dist/welcome-screen.js +43 -14
  20. package/package.json +3 -2
  21. package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.d.ts +2 -0
  22. package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.d.ts.map +1 -0
  23. package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.js +46 -0
  24. package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.js.map +1 -0
  25. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +8 -0
  26. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  27. package/packages/pi-coding-agent/dist/core/agent-session.js +43 -4
  28. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  29. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +3 -1
  30. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  31. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  32. package/packages/pi-coding-agent/dist/core/keybindings.d.ts +1 -1
  33. package/packages/pi-coding-agent/dist/core/keybindings.d.ts.map +1 -1
  34. package/packages/pi-coding-agent/dist/core/keybindings.js +2 -0
  35. package/packages/pi-coding-agent/dist/core/keybindings.js.map +1 -1
  36. package/packages/pi-coding-agent/dist/core/pty-executor.d.ts +48 -0
  37. package/packages/pi-coding-agent/dist/core/pty-executor.d.ts.map +1 -0
  38. package/packages/pi-coding-agent/dist/core/pty-executor.js +173 -0
  39. package/packages/pi-coding-agent/dist/core/pty-executor.js.map +1 -0
  40. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  41. package/packages/pi-coding-agent/dist/core/sdk.js +16 -3
  42. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  43. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +9 -0
  44. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  45. package/packages/pi-coding-agent/dist/core/settings-manager.js +18 -0
  46. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  47. package/packages/pi-coding-agent/dist/core/tool-approval.d.ts.map +1 -1
  48. package/packages/pi-coding-agent/dist/core/tool-approval.js +2 -2
  49. package/packages/pi-coding-agent/dist/core/tool-approval.js.map +1 -1
  50. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +7 -0
  51. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  52. package/packages/pi-coding-agent/dist/core/tools/index.js +23 -2
  53. package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  54. package/packages/pi-coding-agent/dist/core/tools/pty.d.ts +50 -0
  55. package/packages/pi-coding-agent/dist/core/tools/pty.d.ts.map +1 -0
  56. package/packages/pi-coding-agent/dist/core/tools/pty.js +289 -0
  57. package/packages/pi-coding-agent/dist/core/tools/pty.js.map +1 -0
  58. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
  59. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  60. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +36 -22
  61. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  62. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +3 -5
  63. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  64. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +23 -62
  65. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  66. package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  67. package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js +1 -4
  68. package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  69. package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  70. package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js +1 -4
  71. package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  72. package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.d.ts +39 -0
  73. package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.d.ts.map +1 -0
  74. package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.js +182 -0
  75. package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.js.map +1 -0
  76. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +6 -0
  77. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  78. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +36 -0
  79. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  80. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  81. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +2 -4
  82. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  83. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -2
  84. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  85. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +106 -77
  86. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  87. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +2 -5
  88. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  89. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +4 -13
  90. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  91. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts +11 -0
  92. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  93. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +49 -13
  94. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  95. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -1
  96. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +1 -0
  97. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -1
  98. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  99. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +2 -0
  100. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  101. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +3 -0
  102. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  103. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  104. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +27 -0
  105. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  106. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +251 -39
  107. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  108. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +2 -2
  109. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  110. package/packages/pi-coding-agent/dist/utils/terminal-screen.d.ts +10 -0
  111. package/packages/pi-coding-agent/dist/utils/terminal-screen.d.ts.map +1 -0
  112. package/packages/pi-coding-agent/dist/utils/terminal-screen.js +67 -0
  113. package/packages/pi-coding-agent/dist/utils/terminal-screen.js.map +1 -0
  114. package/packages/pi-coding-agent/dist/utils/terminal-serializer.d.ts +7 -0
  115. package/packages/pi-coding-agent/dist/utils/terminal-serializer.d.ts.map +1 -0
  116. package/packages/pi-coding-agent/dist/utils/terminal-serializer.js +67 -0
  117. package/packages/pi-coding-agent/dist/utils/terminal-serializer.js.map +1 -0
  118. package/packages/pi-coding-agent/package.json +9 -4
  119. package/packages/pi-coding-agent/src/core/agent-session.clear-queue.test.ts +50 -0
  120. package/packages/pi-coding-agent/src/core/agent-session.ts +50 -4
  121. package/packages/pi-coding-agent/src/core/extensions/types.ts +1 -1
  122. package/packages/pi-coding-agent/src/core/keybindings.ts +4 -1
  123. package/packages/pi-coding-agent/src/core/pty-executor.ts +229 -0
  124. package/packages/pi-coding-agent/src/core/sdk.ts +16 -3
  125. package/packages/pi-coding-agent/src/core/settings-manager.ts +27 -0
  126. package/packages/pi-coding-agent/src/core/tool-approval.ts +2 -2
  127. package/packages/pi-coding-agent/src/core/tools/index.ts +35 -2
  128. package/packages/pi-coding-agent/src/core/tools/pty.ts +354 -0
  129. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +37 -24
  130. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +22 -70
  131. package/packages/pi-coding-agent/src/modes/interactive/components/branch-summary-message.ts +1 -3
  132. package/packages/pi-coding-agent/src/modes/interactive/components/compaction-summary-message.ts +1 -3
  133. package/packages/pi-coding-agent/src/modes/interactive/components/embedded-terminal.ts +224 -0
  134. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +45 -0
  135. package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +2 -3
  136. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +104 -81
  137. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +5 -19
  138. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +55 -13
  139. package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +1 -0
  140. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +2 -0
  141. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +3 -0
  142. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +296 -48
  143. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +2 -2
  144. package/packages/pi-coding-agent/src/utils/terminal-screen.ts +77 -0
  145. package/packages/pi-coding-agent/src/utils/terminal-serializer.ts +72 -0
  146. package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.d.ts +2 -0
  147. package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.d.ts.map +1 -0
  148. package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.js +105 -0
  149. package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.js.map +1 -0
  150. package/packages/pi-tui/dist/components/editor.d.ts +4 -0
  151. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  152. package/packages/pi-tui/dist/components/editor.js +57 -3
  153. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  154. package/packages/pi-tui/dist/components/loader.d.ts +26 -6
  155. package/packages/pi-tui/dist/components/loader.d.ts.map +1 -1
  156. package/packages/pi-tui/dist/components/loader.js +178 -18
  157. package/packages/pi-tui/dist/components/loader.js.map +1 -1
  158. package/packages/pi-tui/src/components/editor.ts +65 -3
  159. package/packages/pi-tui/src/components/loader.ts +196 -19
  160. package/pkg/dist/modes/interactive/theme/themes.js +2 -2
  161. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  162. package/pkg/package.json +1 -1
  163. package/src/resources/extensions/async-jobs/async-bash-tool.ts +13 -0
  164. package/src/resources/extensions/async-jobs/await-tool.ts +13 -0
  165. package/src/resources/extensions/async-jobs/cancel-job-tool.ts +8 -0
  166. package/src/resources/extensions/cache-timer/index.ts +102 -96
  167. package/src/resources/extensions/codex-rotate/IMPLEMENTATION.md +18 -13
  168. package/src/resources/extensions/codex-rotate/README.md +9 -3
  169. package/src/resources/extensions/codex-rotate/commands.ts +335 -329
  170. package/src/resources/extensions/codex-rotate/index.ts +85 -75
  171. package/src/resources/extensions/memory/auto-extract.ts +330 -204
  172. package/src/resources/extensions/memory/dream.ts +88 -21
  173. package/src/resources/extensions/memory/tests/auto-extract.test.ts +200 -144
  174. package/src/resources/extensions/shared/rtk.js +112 -0
  175. package/src/resources/extensions/subagent/index.ts +35 -6
@@ -7,6 +7,7 @@ type ToolOutputMode = "minimal" | "normal";
7
7
  export declare class BashExecutionComponent extends Container {
8
8
  private command;
9
9
  private outputLines;
10
+ private rawOutput;
10
11
  private status;
11
12
  private exitCode;
12
13
  private loader;
@@ -18,12 +19,9 @@ export declare class BashExecutionComponent extends Container {
18
19
  private ui;
19
20
  private colorKey;
20
21
  private sandboxed;
21
- private rtkActive;
22
- private rtkFlashOn;
23
- private rtkFlashTimer;
24
22
  private headerText;
25
- constructor(command: string, ui: TUI, excludeFromContext?: boolean, renderMode?: ToolOutputMode, rtkActive?: boolean, sandboxed?: boolean);
26
- /** Build the header line text including the RTK badge when active. */
23
+ constructor(command: string, ui: TUI, excludeFromContext?: boolean, renderMode?: ToolOutputMode, _rtkActive?: boolean, sandboxed?: boolean);
24
+ /** Build the header line text. */
27
25
  private buildHeaderText;
28
26
  /**
29
27
  * Stop all timers and release resources. Call when removing the component
@@ -1 +1 @@
1
- {"version":3,"file":"bash-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/bash-execution.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAgB,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,EAGN,KAAK,gBAAgB,EAErB,MAAM,iCAAiC,CAAC;AAYzC,KAAK,cAAc,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE3C,qBAAa,sBAAuB,SAAQ,SAAS;IACpD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,MAAM,CAA6D;IAC3E,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAAC,CAAmB;IAC5C,OAAO,CAAC,cAAc,CAAC,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,EAAE,CAAM;IAChB,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,aAAa,CAA+B;IAEpD,OAAO,CAAC,UAAU,CAAO;gBAGxB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,GAAG,EACP,kBAAkB,UAAQ,EAC1B,UAAU,GAAE,cAAyB,EACrC,SAAS,UAAQ,EACjB,SAAS,UAAQ;IA+ClB,sEAAsE;IACtE,OAAO,CAAC,eAAe;IAcvB;;;OAGG;IACH,OAAO,IAAI,IAAI;IAQf;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAKpC,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAOhC,UAAU,IAAI,IAAI;IAK3B,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAkBjC,WAAW,CACV,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,SAAS,EAAE,OAAO,EAClB,gBAAgB,CAAC,EAAE,gBAAgB,EACnC,cAAc,CAAC,EAAE,MAAM,EACvB,SAAS,CAAC,EAAE,OAAO,GACjB,IAAI;IA4BP,OAAO,CAAC,aAAa;IAqFrB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,UAAU,IAAI,MAAM;CAGpB"}
1
+ {"version":3,"file":"bash-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/bash-execution.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAgB,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAGN,KAAK,gBAAgB,EAErB,MAAM,iCAAiC,CAAC;AASzC,KAAK,cAAc,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE3C,qBAAa,sBAAuB,SAAQ,SAAS;IACpD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,MAAM,CAA6D;IAC3E,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAAC,CAAmB;IAC5C,OAAO,CAAC,cAAc,CAAC,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,EAAE,CAAM;IAChB,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,SAAS,CAAU;IAE3B,OAAO,CAAC,UAAU,CAAO;gBAGxB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,GAAG,EACP,kBAAkB,UAAQ,EAC1B,UAAU,GAAE,cAAyB,EACrC,UAAU,UAAQ,EAClB,SAAS,UAAQ;IA6BlB,kCAAkC;IAClC,OAAO,CAAC,eAAe;IAQvB;;;OAGG;IACH,OAAO,IAAI,IAAI;IAIf;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAKpC,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAOhC,UAAU,IAAI,IAAI;IAK3B,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAOjC,WAAW,CACV,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,SAAS,EAAE,OAAO,EAClB,gBAAgB,CAAC,EAAE,gBAAgB,EACnC,cAAc,CAAC,EAAE,MAAM,EACvB,SAAS,CAAC,EAAE,OAAO,GACjB,IAAI;IAmBP,OAAO,CAAC,aAAa;IA2FrB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,UAAU,IAAI,MAAM;CAGpB"}
@@ -2,68 +2,43 @@
2
2
  * Component for displaying bash command execution with streaming output.
3
3
  */
4
4
  import { Container, Loader, Text } from "@gsd/pi-tui";
5
- import stripAnsi from "strip-ansi";
6
5
  import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, truncateTail, } from "../../../core/tools/truncate.js";
6
+ import { renderTerminalLines } from "../../../utils/terminal-serializer.js";
7
7
  import { theme } from "../theme/theme.js";
8
- import { DynamicBorder } from "./dynamic-border.js";
9
8
  import { editorKey, keyHint } from "./keybinding-hints.js";
10
9
  import { truncateToVisualLines } from "./visual-truncate.js";
11
- // Flash interval for RTK badge animation (ms)
12
- const RTK_FLASH_INTERVAL_MS = 400;
13
10
  // Preview line limit when not expanded (matches tool execution behavior)
14
11
  const PREVIEW_LINES = 20;
15
12
  export class BashExecutionComponent extends Container {
16
- constructor(command, ui, excludeFromContext = false, renderMode = "normal", rtkActive = false, sandboxed = false) {
13
+ constructor(command, ui, excludeFromContext = false, renderMode = "normal", _rtkActive = false, sandboxed = false) {
17
14
  super();
18
15
  this.outputLines = [];
16
+ this.rawOutput = "";
19
17
  this.status = "running";
20
18
  this.exitCode = undefined;
21
19
  this.expanded = false;
22
- this.rtkFlashOn = true;
23
- this.rtkFlashTimer = null;
24
20
  this.command = command;
25
21
  this.ui = ui;
26
22
  this.renderMode = renderMode;
27
- this.rtkActive = rtkActive;
28
23
  this.sandboxed = sandboxed;
29
- // Use dim border for excluded-from-context commands (!! prefix)
24
+ // Use dim tone for excluded-from-context commands (!! prefix)
30
25
  this.colorKey = (excludeFromContext ? "dim" : "bashMode");
31
- const borderColor = (str) => theme.fg(this.colorKey, str);
32
- // Top border
33
- this.addChild(new DynamicBorder(borderColor));
34
- // Content container (holds dynamic content between borders)
26
+ // Content container
35
27
  this.contentContainer = new Container();
36
28
  this.addChild(this.contentContainer);
37
- // Dedicated header Text node — updated directly for flash without full rebuild
29
+ // Header Text node
38
30
  this.headerText = new Text(this.buildHeaderText(), 1, 0);
39
31
  this.contentContainer.addChild(this.headerText);
40
32
  // Loader
41
33
  this.loader = new Loader(ui, (spinner) => theme.fg(this.colorKey, spinner), (text) => theme.fg("muted", text), `Running... (${editorKey("selectCancel")} to cancel)`);
42
34
  this.contentContainer.addChild(this.loader);
43
- // Bottom border
44
- this.addChild(new DynamicBorder(borderColor));
45
- // Start RTK flash animation if active
46
- if (this.rtkActive) {
47
- this.rtkFlashTimer = setInterval(() => {
48
- this.rtkFlashOn = !this.rtkFlashOn;
49
- // Only update the header node — no full container rebuild
50
- this.headerText.setText(this.buildHeaderText());
51
- this.ui.requestRender();
52
- }, RTK_FLASH_INTERVAL_MS);
53
- }
54
35
  }
55
- /** Build the header line text including the RTK badge when active. */
36
+ /** Build the header line text. */
56
37
  buildHeaderText() {
57
- let text = theme.fg(this.colorKey, theme.bold(`$ ${this.command}`));
38
+ let text = `${theme.fg("toolTitle", theme.bold("bash"))} ${theme.fg(this.colorKey, theme.bold(`$ ${this.command}`))}`;
58
39
  if (this.sandboxed) {
59
40
  text += ` ${theme.fg("success", "[sandboxed]")}`;
60
41
  }
61
- if (this.rtkActive) {
62
- const badge = this.rtkFlashOn
63
- ? theme.fg("accent", "$ RTK")
64
- : theme.fg("dim", "$ RTK");
65
- text = `${text} ${badge}`;
66
- }
67
42
  return text;
68
43
  }
69
44
  /**
@@ -71,10 +46,6 @@ export class BashExecutionComponent extends Container {
71
46
  * from the tree before setComplete() has been called (e.g. on clear/cancel).
72
47
  */
73
48
  dispose() {
74
- if (this.rtkFlashTimer) {
75
- clearInterval(this.rtkFlashTimer);
76
- this.rtkFlashTimer = null;
77
- }
78
49
  this.loader.dispose();
79
50
  }
80
51
  /**
@@ -95,19 +66,9 @@ export class BashExecutionComponent extends Container {
95
66
  this.updateDisplay();
96
67
  }
97
68
  appendOutput(chunk) {
98
- // Strip ANSI codes and normalize line endings
99
- // Note: binary data is already sanitized in tui-renderer.ts executeBashCommand
100
- const clean = stripAnsi(chunk).replace(/\r\n/g, "\n").replace(/\r/g, "\n");
101
- // Append to output lines
102
- const newLines = clean.split("\n");
103
- if (this.outputLines.length > 0 && newLines.length > 0) {
104
- // Append first chunk to last line (incomplete line continuation)
105
- this.outputLines[this.outputLines.length - 1] += newLines[0];
106
- this.outputLines.push(...newLines.slice(1));
107
- }
108
- else {
109
- this.outputLines.push(...newLines);
110
- }
69
+ // Strip ANSI codes and preserve carriage-return semantics for display.
70
+ this.rawOutput += chunk;
71
+ this.outputLines = renderTerminalLines(this.rawOutput);
111
72
  this.updateDisplay();
112
73
  }
113
74
  setComplete(exitCode, cancelled, truncationResult, fullOutputPath, sandboxed) {
@@ -124,14 +85,6 @@ export class BashExecutionComponent extends Container {
124
85
  }
125
86
  // Stop loader
126
87
  this.loader.stop();
127
- // Stop RTK flash — settle to steady dim state
128
- if (this.rtkFlashTimer) {
129
- clearInterval(this.rtkFlashTimer);
130
- this.rtkFlashTimer = null;
131
- this.rtkFlashOn = false;
132
- // Final header update to ensure dim badge is shown
133
- this.headerText.setText(this.buildHeaderText());
134
- }
135
88
  this.updateDisplay();
136
89
  }
137
90
  updateDisplay() {
@@ -158,7 +111,7 @@ export class BashExecutionComponent extends Container {
158
111
  this.contentContainer.addChild(new Text(`\n${displayText}`, 1, 0));
159
112
  }
160
113
  else if (this.renderMode === "minimal") {
161
- this.contentContainer.addChild(new Text(`\n${theme.fg("muted", `(${keyHint("expandTools", "to expand")})`)}`, 1, 0));
114
+ // collapsed — no inline hint needed (shown in editor bottom border)
162
115
  }
163
116
  else {
164
117
  // Use shared visual truncation utility
@@ -173,14 +126,22 @@ export class BashExecutionComponent extends Container {
173
126
  }
174
127
  else {
175
128
  const statusParts = [];
176
- // Show how many lines are hidden (collapsed preview)
177
- if (hiddenLineCount > 0) {
129
+ // Show expand/collapse hint whenever there is output
130
+ if (availableLines.length > 0) {
178
131
  if (this.expanded) {
179
132
  statusParts.push(`(${keyHint("expandTools", "to collapse")})`);
180
133
  }
181
- else {
134
+ else if (this.renderMode === "minimal") {
135
+ statusParts.push(`(${keyHint("expandTools", "to expand")})`);
136
+ }
137
+ else if (hiddenLineCount > 0) {
138
+ // Normal mode: show line count + hint
182
139
  statusParts.push(`${theme.fg("muted", `... ${hiddenLineCount} more lines`)} (${keyHint("expandTools", "to expand")})`);
183
140
  }
141
+ else {
142
+ // Normal mode: all preview lines visible, still offer expand
143
+ statusParts.push(`(${keyHint("expandTools", "to expand")})`);
144
+ }
184
145
  }
185
146
  if (this.status === "cancelled") {
186
147
  statusParts.push(theme.fg("warning", "(cancelled)"));
@@ -1 +1 @@
1
- {"version":3,"file":"bash-execution.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/bash-execution.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Component for displaying bash command execution with streaming output.\n */\n\nimport { Container, Loader, Text, type TUI } from \"@gsd/pi-tui\";\nimport stripAnsi from \"strip-ansi\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\ttype TruncationResult,\n\ttruncateTail,\n} from \"../../../core/tools/truncate.js\";\nimport { theme, type ThemeColor } from \"../theme/theme.js\";\nimport { DynamicBorder } from \"./dynamic-border.js\";\nimport { editorKey, keyHint } from \"./keybinding-hints.js\";\nimport { truncateToVisualLines } from \"./visual-truncate.js\";\n\n// Flash interval for RTK badge animation (ms)\nconst RTK_FLASH_INTERVAL_MS = 400;\n\n// Preview line limit when not expanded (matches tool execution behavior)\nconst PREVIEW_LINES = 20;\n\ntype ToolOutputMode = \"minimal\" | \"normal\";\n\nexport class BashExecutionComponent extends Container {\n\tprivate command: string;\n\tprivate outputLines: string[] = [];\n\tprivate status: \"running\" | \"complete\" | \"cancelled\" | \"error\" = \"running\";\n\tprivate exitCode: number | undefined = undefined;\n\tprivate loader: Loader;\n\tprivate truncationResult?: TruncationResult;\n\tprivate fullOutputPath?: string;\n\tprivate expanded = false;\n\tprivate renderMode: ToolOutputMode;\n\tprivate contentContainer: Container;\n\tprivate ui: TUI;\n\tprivate colorKey: ThemeColor;\n\tprivate sandboxed: boolean;\n\tprivate rtkActive: boolean;\n\tprivate rtkFlashOn = true;\n\tprivate rtkFlashTimer: NodeJS.Timeout | null = null;\n\t// Dedicated header node — updated in-place to avoid full container rebuild on flash tick\n\tprivate headerText: Text;\n\n\tconstructor(\n\t\tcommand: string,\n\t\tui: TUI,\n\t\texcludeFromContext = false,\n\t\trenderMode: ToolOutputMode = \"normal\",\n\t\trtkActive = false,\n\t\tsandboxed = false,\n\t) {\n\t\tsuper();\n\t\tthis.command = command;\n\t\tthis.ui = ui;\n\t\tthis.renderMode = renderMode;\n\t\tthis.rtkActive = rtkActive;\n\t\tthis.sandboxed = sandboxed;\n\n\t\t// Use dim border for excluded-from-context commands (!! prefix)\n\t\tthis.colorKey = (excludeFromContext ? \"dim\" : \"bashMode\") as ThemeColor;\n\t\tconst borderColor = (str: string) => theme.fg(this.colorKey, str);\n\n\t\t// Top border\n\t\tthis.addChild(new DynamicBorder(borderColor));\n\n\t\t// Content container (holds dynamic content between borders)\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\t// Dedicated header Text node — updated directly for flash without full rebuild\n\t\tthis.headerText = new Text(this.buildHeaderText(), 1, 0);\n\t\tthis.contentContainer.addChild(this.headerText);\n\n\t\t// Loader\n\t\tthis.loader = new Loader(\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(this.colorKey, spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\t`Running... (${editorKey(\"selectCancel\")} to cancel)`, // Plain text for loader\n\t\t);\n\t\tthis.contentContainer.addChild(this.loader);\n\n\t\t// Bottom border\n\t\tthis.addChild(new DynamicBorder(borderColor));\n\n\t\t// Start RTK flash animation if active\n\t\tif (this.rtkActive) {\n\t\t\tthis.rtkFlashTimer = setInterval(() => {\n\t\t\t\tthis.rtkFlashOn = !this.rtkFlashOn;\n\t\t\t\t// Only update the header node — no full container rebuild\n\t\t\t\tthis.headerText.setText(this.buildHeaderText());\n\t\t\t\tthis.ui.requestRender();\n\t\t\t}, RTK_FLASH_INTERVAL_MS);\n\t\t}\n\t}\n\n\t/** Build the header line text including the RTK badge when active. */\n\tprivate buildHeaderText(): string {\n\t\tlet text = theme.fg(this.colorKey, theme.bold(`$ ${this.command}`));\n\t\tif (this.sandboxed) {\n\t\t\ttext += ` ${theme.fg(\"success\", \"[sandboxed]\")}`;\n\t\t}\n\t\tif (this.rtkActive) {\n\t\t\tconst badge = this.rtkFlashOn\n\t\t\t\t? theme.fg(\"accent\", \"$ RTK\")\n\t\t\t\t: theme.fg(\"dim\", \"$ RTK\");\n\t\t\ttext = `${text} ${badge}`;\n\t\t}\n\t\treturn text;\n\t}\n\n\t/**\n\t * Stop all timers and release resources. Call when removing the component\n\t * from the tree before setComplete() has been called (e.g. on clear/cancel).\n\t */\n\tdispose(): void {\n\t\tif (this.rtkFlashTimer) {\n\t\t\tclearInterval(this.rtkFlashTimer);\n\t\t\tthis.rtkFlashTimer = null;\n\t\t}\n\t\tthis.loader.dispose();\n\t}\n\n\t/**\n\t * Set whether the output is expanded (shows full output) or collapsed (preview only).\n\t */\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetRenderMode(mode: ToolOutputMode): void {\n\t\tif (this.renderMode !== mode) {\n\t\t\tthis.renderMode = mode;\n\t\t\tthis.updateDisplay();\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tappendOutput(chunk: string): void {\n\t\t// Strip ANSI codes and normalize line endings\n\t\t// Note: binary data is already sanitized in tui-renderer.ts executeBashCommand\n\t\tconst clean = stripAnsi(chunk).replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n\n\t\t// Append to output lines\n\t\tconst newLines = clean.split(\"\\n\");\n\t\tif (this.outputLines.length > 0 && newLines.length > 0) {\n\t\t\t// Append first chunk to last line (incomplete line continuation)\n\t\t\tthis.outputLines[this.outputLines.length - 1] += newLines[0];\n\t\t\tthis.outputLines.push(...newLines.slice(1));\n\t\t} else {\n\t\t\tthis.outputLines.push(...newLines);\n\t\t}\n\n\t\tthis.updateDisplay();\n\t}\n\n\tsetComplete(\n\t\texitCode: number | undefined,\n\t\tcancelled: boolean,\n\t\ttruncationResult?: TruncationResult,\n\t\tfullOutputPath?: string,\n\t\tsandboxed?: boolean,\n\t): void {\n\t\tthis.exitCode = exitCode;\n\t\tthis.status = cancelled\n\t\t\t? \"cancelled\"\n\t\t\t: exitCode !== 0 && exitCode !== undefined && exitCode !== null\n\t\t\t\t? \"error\"\n\t\t\t\t: \"complete\";\n\t\tthis.truncationResult = truncationResult;\n\t\tthis.fullOutputPath = fullOutputPath;\n\t\tif (sandboxed !== undefined) {\n\t\t\tthis.sandboxed = sandboxed;\n\t\t}\n\n\t\t// Stop loader\n\t\tthis.loader.stop();\n\n\t\t// Stop RTK flash — settle to steady dim state\n\t\tif (this.rtkFlashTimer) {\n\t\t\tclearInterval(this.rtkFlashTimer);\n\t\t\tthis.rtkFlashTimer = null;\n\t\t\tthis.rtkFlashOn = false;\n\t\t\t// Final header update to ensure dim badge is shown\n\t\t\tthis.headerText.setText(this.buildHeaderText());\n\t\t}\n\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\t// Apply truncation for LLM context limits (same limits as bash tool)\n\t\tconst fullOutput = this.outputLines.join(\"\\n\");\n\t\tconst contextTruncation = truncateTail(fullOutput, {\n\t\t\tmaxLines: DEFAULT_MAX_LINES,\n\t\t\tmaxBytes: DEFAULT_MAX_BYTES,\n\t\t});\n\n\t\t// Get the lines to potentially display (after context truncation)\n\t\tconst availableLines = contextTruncation.content ? contextTruncation.content.split(\"\\n\") : [];\n\n\t\t// Apply preview truncation based on expanded state\n\t\tconst previewLogicalLines = availableLines.slice(-PREVIEW_LINES);\n\t\tconst hiddenLineCount = availableLines.length - previewLogicalLines.length;\n\n\t\t// Rebuild content container\n\t\tthis.contentContainer.clear();\n\n\t\t// Header — re-add the dedicated node (clear() removed it, setText keeps its current value)\n\t\tthis.contentContainer.addChild(this.headerText);\n\n\t\t// Output\n\t\tif (availableLines.length > 0) {\n\t\t\tif (this.expanded) {\n\t\t\t\t// Show all lines\n\t\t\t\tconst displayText = availableLines.map((line) => theme.fg(\"muted\", line)).join(\"\\n\");\n\t\t\t\tthis.contentContainer.addChild(new Text(`\\n${displayText}`, 1, 0));\n\t\t\t} else if (this.renderMode === \"minimal\") {\n\t\t\t\tthis.contentContainer.addChild(new Text(`\\n${theme.fg(\"muted\", `(${keyHint(\"expandTools\", \"to expand\")})`)}`, 1, 0));\n\t\t\t} else {\n\t\t\t\t// Use shared visual truncation utility\n\t\t\t\tconst styledOutput = previewLogicalLines.map((line) => theme.fg(\"muted\", line)).join(\"\\n\");\n\t\t\t\tconst { visualLines } = truncateToVisualLines(\n\t\t\t\t\t`\\n${styledOutput}`,\n\t\t\t\t\tPREVIEW_LINES,\n\t\t\t\t\tthis.ui.terminal.columns,\n\t\t\t\t\t1, // padding\n\t\t\t\t);\n\t\t\t\tthis.contentContainer.addChild({ render: () => visualLines, invalidate: () => {} });\n\t\t\t}\n\t\t}\n\n\t\t// Loader or status\n\t\tif (this.status === \"running\") {\n\t\t\tthis.contentContainer.addChild(this.loader);\n\t\t} else {\n\t\t\tconst statusParts: string[] = [];\n\n\t\t\t// Show how many lines are hidden (collapsed preview)\n\t\t\tif (hiddenLineCount > 0) {\n\t\t\t\tif (this.expanded) {\n\t\t\t\t\tstatusParts.push(`(${keyHint(\"expandTools\", \"to collapse\")})`);\n\t\t\t\t} else {\n\t\t\t\t\tstatusParts.push(\n\t\t\t\t\t\t`${theme.fg(\"muted\", `... ${hiddenLineCount} more lines`)} (${keyHint(\"expandTools\", \"to expand\")})`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.status === \"cancelled\") {\n\t\t\t\tstatusParts.push(theme.fg(\"warning\", \"(cancelled)\"));\n\t\t\t} else if (this.status === \"error\") {\n\t\t\t\tstatusParts.push(theme.fg(\"error\", `(exit ${this.exitCode})`));\n\t\t\t\tif (this.sandboxed && /operation not permitted/i.test(fullOutput)) {\n\t\t\t\t\tstatusParts.push(\n\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\"Sandbox blocked this operation. Run /sandbox to inspect the active policy and allowed paths.\",\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add truncation warning (context truncation, not preview truncation)\n\t\t\tconst wasTruncated = this.truncationResult?.truncated || contextTruncation.truncated;\n\t\t\tif (wasTruncated && this.fullOutputPath) {\n\t\t\t\tstatusParts.push(theme.fg(\"warning\", `Output truncated. Full output: ${this.fullOutputPath}`));\n\t\t\t}\n\n\t\t\tif (statusParts.length > 0) {\n\t\t\t\tthis.contentContainer.addChild(new Text(`\\n${statusParts.join(\"\\n\")}`, 1, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the raw output for creating BashExecutionMessage.\n\t */\n\tgetOutput(): string {\n\t\treturn this.outputLines.join(\"\\n\");\n\t}\n\n\t/**\n\t * Get the command that was executed.\n\t */\n\tgetCommand(): string {\n\t\treturn this.command;\n\t}\n}\n"]}
1
+ {"version":3,"file":"bash-execution.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/bash-execution.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Component for displaying bash command execution with streaming output.\n */\n\nimport { Container, Loader, Text, type TUI } from \"@gsd/pi-tui\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\ttype TruncationResult,\n\ttruncateTail,\n} from \"../../../core/tools/truncate.js\";\nimport { renderTerminalLines } from \"../../../utils/terminal-serializer.js\";\nimport { theme, type ThemeColor } from \"../theme/theme.js\";\nimport { editorKey, keyHint } from \"./keybinding-hints.js\";\nimport { truncateToVisualLines } from \"./visual-truncate.js\";\n\n// Preview line limit when not expanded (matches tool execution behavior)\nconst PREVIEW_LINES = 20;\n\ntype ToolOutputMode = \"minimal\" | \"normal\";\n\nexport class BashExecutionComponent extends Container {\n\tprivate command: string;\n\tprivate outputLines: string[] = [];\n\tprivate rawOutput = \"\";\n\tprivate status: \"running\" | \"complete\" | \"cancelled\" | \"error\" = \"running\";\n\tprivate exitCode: number | undefined = undefined;\n\tprivate loader: Loader;\n\tprivate truncationResult?: TruncationResult;\n\tprivate fullOutputPath?: string;\n\tprivate expanded = false;\n\tprivate renderMode: ToolOutputMode;\n\tprivate contentContainer: Container;\n\tprivate ui: TUI;\n\tprivate colorKey: ThemeColor;\n\tprivate sandboxed: boolean;\n\t// Dedicated header node\n\tprivate headerText: Text;\n\n\tconstructor(\n\t\tcommand: string,\n\t\tui: TUI,\n\t\texcludeFromContext = false,\n\t\trenderMode: ToolOutputMode = \"normal\",\n\t\t_rtkActive = false,\n\t\tsandboxed = false,\n\t) {\n\t\tsuper();\n\t\tthis.command = command;\n\t\tthis.ui = ui;\n\t\tthis.renderMode = renderMode;\n\t\tthis.sandboxed = sandboxed;\n\n\t\t// Use dim tone for excluded-from-context commands (!! prefix)\n\t\tthis.colorKey = (excludeFromContext ? \"dim\" : \"bashMode\") as ThemeColor;\n\n\t\t// Content container\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\t// Header Text node\n\t\tthis.headerText = new Text(this.buildHeaderText(), 1, 0);\n\t\tthis.contentContainer.addChild(this.headerText);\n\n\t\t// Loader\n\t\tthis.loader = new Loader(\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(this.colorKey, spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\t`Running... (${editorKey(\"selectCancel\")} to cancel)`, // Plain text for loader\n\t\t);\n\t\tthis.contentContainer.addChild(this.loader);\n\t}\n\n\t/** Build the header line text. */\n\tprivate buildHeaderText(): string {\n\t\tlet text = `${theme.fg(\"toolTitle\", theme.bold(\"bash\"))} ${theme.fg(this.colorKey, theme.bold(`$ ${this.command}`))}`;\n\t\tif (this.sandboxed) {\n\t\t\ttext += ` ${theme.fg(\"success\", \"[sandboxed]\")}`;\n\t\t}\n\t\treturn text;\n\t}\n\n\t/**\n\t * Stop all timers and release resources. Call when removing the component\n\t * from the tree before setComplete() has been called (e.g. on clear/cancel).\n\t */\n\tdispose(): void {\n\t\tthis.loader.dispose();\n\t}\n\n\t/**\n\t * Set whether the output is expanded (shows full output) or collapsed (preview only).\n\t */\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetRenderMode(mode: ToolOutputMode): void {\n\t\tif (this.renderMode !== mode) {\n\t\t\tthis.renderMode = mode;\n\t\t\tthis.updateDisplay();\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tappendOutput(chunk: string): void {\n\t\t// Strip ANSI codes and preserve carriage-return semantics for display.\n\t\tthis.rawOutput += chunk;\n\t\tthis.outputLines = renderTerminalLines(this.rawOutput);\n\t\tthis.updateDisplay();\n\t}\n\n\tsetComplete(\n\t\texitCode: number | undefined,\n\t\tcancelled: boolean,\n\t\ttruncationResult?: TruncationResult,\n\t\tfullOutputPath?: string,\n\t\tsandboxed?: boolean,\n\t): void {\n\t\tthis.exitCode = exitCode;\n\t\tthis.status = cancelled\n\t\t\t? \"cancelled\"\n\t\t\t: exitCode !== 0 && exitCode !== undefined && exitCode !== null\n\t\t\t\t? \"error\"\n\t\t\t\t: \"complete\";\n\t\tthis.truncationResult = truncationResult;\n\t\tthis.fullOutputPath = fullOutputPath;\n\t\tif (sandboxed !== undefined) {\n\t\t\tthis.sandboxed = sandboxed;\n\t\t}\n\n\t\t// Stop loader\n\t\tthis.loader.stop();\n\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\t// Apply truncation for LLM context limits (same limits as bash tool)\n\t\tconst fullOutput = this.outputLines.join(\"\\n\");\n\t\tconst contextTruncation = truncateTail(fullOutput, {\n\t\t\tmaxLines: DEFAULT_MAX_LINES,\n\t\t\tmaxBytes: DEFAULT_MAX_BYTES,\n\t\t});\n\n\t\t// Get the lines to potentially display (after context truncation)\n\t\tconst availableLines = contextTruncation.content ? contextTruncation.content.split(\"\\n\") : [];\n\n\t\t// Apply preview truncation based on expanded state\n\t\tconst previewLogicalLines = availableLines.slice(-PREVIEW_LINES);\n\t\tconst hiddenLineCount = availableLines.length - previewLogicalLines.length;\n\n\t\t// Rebuild content container\n\t\tthis.contentContainer.clear();\n\n\t\t// Header — re-add the dedicated node (clear() removed it, setText keeps its current value)\n\t\tthis.contentContainer.addChild(this.headerText);\n\n\t\t// Output\n\t\tif (availableLines.length > 0) {\n\t\t\tif (this.expanded) {\n\t\t\t\t// Show all lines\n\t\t\t\tconst displayText = availableLines.map((line) => theme.fg(\"muted\", line)).join(\"\\n\");\n\t\t\t\tthis.contentContainer.addChild(new Text(`\\n${displayText}`, 1, 0));\n\t\t\t} else if (this.renderMode === \"minimal\") {\n\t\t\t\t// collapsed — no inline hint needed (shown in editor bottom border)\n\t\t\t} else {\n\t\t\t\t// Use shared visual truncation utility\n\t\t\t\tconst styledOutput = previewLogicalLines.map((line) => theme.fg(\"muted\", line)).join(\"\\n\");\n\t\t\t\tconst { visualLines } = truncateToVisualLines(\n\t\t\t\t\t`\\n${styledOutput}`,\n\t\t\t\t\tPREVIEW_LINES,\n\t\t\t\t\tthis.ui.terminal.columns,\n\t\t\t\t\t1, // padding\n\t\t\t\t);\n\t\t\t\tthis.contentContainer.addChild({ render: () => visualLines, invalidate: () => {} });\n\t\t\t}\n\t\t}\n\n\t\t// Loader or status\n\t\tif (this.status === \"running\") {\n\t\t\tthis.contentContainer.addChild(this.loader);\n\t\t} else {\n\t\t\tconst statusParts: string[] = [];\n\n\t\t\t// Show expand/collapse hint whenever there is output\n\t\t\tif (availableLines.length > 0) {\n\t\t\t\tif (this.expanded) {\n\t\t\t\t\tstatusParts.push(`(${keyHint(\"expandTools\", \"to collapse\")})`);\n\t\t\t\t} else if (this.renderMode === \"minimal\") {\n\t\t\t\t\tstatusParts.push(`(${keyHint(\"expandTools\", \"to expand\")})`);\n\t\t\t\t} else if (hiddenLineCount > 0) {\n\t\t\t\t\t// Normal mode: show line count + hint\n\t\t\t\t\tstatusParts.push(\n\t\t\t\t\t\t`${theme.fg(\"muted\", `... ${hiddenLineCount} more lines`)} (${keyHint(\"expandTools\", \"to expand\")})`,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t// Normal mode: all preview lines visible, still offer expand\n\t\t\t\t\tstatusParts.push(`(${keyHint(\"expandTools\", \"to expand\")})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.status === \"cancelled\") {\n\t\t\t\tstatusParts.push(theme.fg(\"warning\", \"(cancelled)\"));\n\t\t\t} else if (this.status === \"error\") {\n\t\t\t\tstatusParts.push(theme.fg(\"error\", `(exit ${this.exitCode})`));\n\t\t\t\tif (this.sandboxed && /operation not permitted/i.test(fullOutput)) {\n\t\t\t\t\tstatusParts.push(\n\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\"Sandbox blocked this operation. Run /sandbox to inspect the active policy and allowed paths.\",\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add truncation warning (context truncation, not preview truncation)\n\t\t\tconst wasTruncated = this.truncationResult?.truncated || contextTruncation.truncated;\n\t\t\tif (wasTruncated && this.fullOutputPath) {\n\t\t\t\tstatusParts.push(theme.fg(\"warning\", `Output truncated. Full output: ${this.fullOutputPath}`));\n\t\t\t}\n\n\t\t\tif (statusParts.length > 0) {\n\t\t\t\tthis.contentContainer.addChild(new Text(`\\n${statusParts.join(\"\\n\")}`, 1, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the raw output for creating BashExecutionMessage.\n\t */\n\tgetOutput(): string {\n\t\treturn this.outputLines.join(\"\\n\");\n\t}\n\n\t/**\n\t * Get the command that was executed.\n\t */\n\tgetCommand(): string {\n\t\treturn this.command;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"branch-summary-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/branch-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAY,KAAK,aAAa,EAAgB,MAAM,aAAa,CAAC;AAC9E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAItE;;;GAGG;AACH,qBAAa,6BAA8B,SAAQ,GAAG;IACrD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,aAAa,CAAgB;gBAEzB,OAAO,EAAE,oBAAoB,EAAE,aAAa,GAAE,aAAkC;IAO5F,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAK3B,UAAU,IAAI,IAAI;IAK3B,OAAO,CAAC,aAAa;CA0BrB"}
1
+ {"version":3,"file":"branch-summary-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/branch-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAY,KAAK,aAAa,EAAgB,MAAM,aAAa,CAAC;AAC9E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAItE;;;GAGG;AACH,qBAAa,6BAA8B,SAAQ,GAAG;IACrD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,aAAa,CAAgB;gBAEzB,OAAO,EAAE,oBAAoB,EAAE,aAAa,GAAE,aAAkC;IAO5F,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAK3B,UAAU,IAAI,IAAI;IAK3B,OAAO,CAAC,aAAa;CAwBrB"}
@@ -1,6 +1,5 @@
1
1
  import { Box, Markdown, Spacer, Text } from "@gsd/pi-tui";
2
2
  import { getMarkdownTheme, theme } from "../theme/theme.js";
3
- import { editorKey } from "./keybinding-hints.js";
4
3
  /**
5
4
  * Component that renders a branch summary message with collapsed/expanded state.
6
5
  * Uses same background color as custom messages for visual consistency.
@@ -33,9 +32,7 @@ export class BranchSummaryMessageComponent extends Box {
33
32
  }));
34
33
  }
35
34
  else {
36
- this.addChild(new Text(theme.fg("customMessageText", "Branch summary (") +
37
- theme.fg("dim", editorKey("expandTools")) +
38
- theme.fg("customMessageText", " to expand)"), 0, 0));
35
+ this.addChild(new Text(theme.fg("customMessageText", "Branch summary"), 0, 0));
39
36
  }
40
37
  }
41
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"branch-summary-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/branch-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAsB,MAAM,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAE9E,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;GAGG;AACH,MAAM,OAAO,6BAA8B,SAAQ,GAAG;IAKrD,YAAY,OAA6B,EAAE,gBAA+B,gBAAgB,EAAE;QAC3F,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,CAAC;QAL5C,aAAQ,GAAG,KAAK,CAAC;QAMxB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAED,WAAW,CAAC,QAAiB;QAC5B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAEQ,UAAU;QAClB,KAAK,CAAC,UAAU,EAAE,CAAC;QACnB,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAEO,aAAa;QACpB,IAAI,CAAC,KAAK,EAAE,CAAC;QAEb,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,oBAAoB,EAAE,yBAAyB,CAAC,CAAC;QACxE,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACrC,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,MAAM,GAAG,wBAAwB,CAAC;YACxC,IAAI,CAAC,QAAQ,CACZ,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE;gBACrE,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,IAAI,CAAC;aAC5D,CAAC,CACF,CAAC;QACH,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,QAAQ,CACZ,IAAI,IAAI,CACP,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,kBAAkB,CAAC;gBAChD,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,aAAa,CAAC,CAAC;gBACzC,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,aAAa,CAAC,EAC7C,CAAC,EACD,CAAC,CACD,CACD,CAAC;QACH,CAAC;IACF,CAAC;CACD","sourcesContent":["import { Box, Markdown, type MarkdownTheme, Spacer, Text } from \"@gsd/pi-tui\";\nimport type { BranchSummaryMessage } from \"../../../core/messages.js\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.js\";\nimport { editorKey } from \"./keybinding-hints.js\";\n\n/**\n * Component that renders a branch summary message with collapsed/expanded state.\n * Uses same background color as custom messages for visual consistency.\n */\nexport class BranchSummaryMessageComponent extends Box {\n\tprivate expanded = false;\n\tprivate message: BranchSummaryMessage;\n\tprivate markdownTheme: MarkdownTheme;\n\n\tconstructor(message: BranchSummaryMessage, markdownTheme: MarkdownTheme = getMarkdownTheme()) {\n\t\tsuper(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\t\tthis.message = message;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.clear();\n\n\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[branch]\\x1b[22m`);\n\t\tthis.addChild(new Text(label, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (this.expanded) {\n\t\t\tconst header = \"**Branch Summary**\\n\\n\";\n\t\t\tthis.addChild(\n\t\t\t\tnew Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\"customMessageText\", \"Branch summary (\") +\n\t\t\t\t\t\ttheme.fg(\"dim\", editorKey(\"expandTools\")) +\n\t\t\t\t\t\ttheme.fg(\"customMessageText\", \" to expand)\"),\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"branch-summary-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/branch-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAsB,MAAM,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAE9E,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAG5D;;;GAGG;AACH,MAAM,OAAO,6BAA8B,SAAQ,GAAG;IAKrD,YAAY,OAA6B,EAAE,gBAA+B,gBAAgB,EAAE;QAC3F,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,CAAC;QAL5C,aAAQ,GAAG,KAAK,CAAC;QAMxB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAED,WAAW,CAAC,QAAiB;QAC5B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAEQ,UAAU;QAClB,KAAK,CAAC,UAAU,EAAE,CAAC;QACnB,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAEO,aAAa;QACpB,IAAI,CAAC,KAAK,EAAE,CAAC;QAEb,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,oBAAoB,EAAE,yBAAyB,CAAC,CAAC;QACxE,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACrC,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,MAAM,GAAG,wBAAwB,CAAC;YACxC,IAAI,CAAC,QAAQ,CACZ,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE;gBACrE,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,IAAI,CAAC;aAC5D,CAAC,CACF,CAAC;QACH,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,QAAQ,CACZ,IAAI,IAAI,CACP,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,EAC/C,CAAC,EACD,CAAC,CACD,CACD,CAAC;QACH,CAAC;IACF,CAAC;CACD","sourcesContent":["import { Box, Markdown, type MarkdownTheme, Spacer, Text } from \"@gsd/pi-tui\";\nimport type { BranchSummaryMessage } from \"../../../core/messages.js\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.js\";\nimport { editorKey } from \"./keybinding-hints.js\";\n\n/**\n * Component that renders a branch summary message with collapsed/expanded state.\n * Uses same background color as custom messages for visual consistency.\n */\nexport class BranchSummaryMessageComponent extends Box {\n\tprivate expanded = false;\n\tprivate message: BranchSummaryMessage;\n\tprivate markdownTheme: MarkdownTheme;\n\n\tconstructor(message: BranchSummaryMessage, markdownTheme: MarkdownTheme = getMarkdownTheme()) {\n\t\tsuper(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\t\tthis.message = message;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.clear();\n\n\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[branch]\\x1b[22m`);\n\t\tthis.addChild(new Text(label, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (this.expanded) {\n\t\t\tconst header = \"**Branch Summary**\\n\\n\";\n\t\t\tthis.addChild(\n\t\t\t\tnew Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\"customMessageText\", \"Branch summary\"),\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"compaction-summary-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/compaction-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAY,KAAK,aAAa,EAAgB,MAAM,aAAa,CAAC;AAC9E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAI1E;;;GAGG;AACH,qBAAa,iCAAkC,SAAQ,GAAG;IACzD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,aAAa,CAAgB;gBAEzB,OAAO,EAAE,wBAAwB,EAAE,aAAa,GAAE,aAAkC;IAOhG,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAK3B,UAAU,IAAI,IAAI;IAK3B,OAAO,CAAC,aAAa;CA2BrB"}
1
+ {"version":3,"file":"compaction-summary-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/compaction-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAY,KAAK,aAAa,EAAgB,MAAM,aAAa,CAAC;AAC9E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAI1E;;;GAGG;AACH,qBAAa,iCAAkC,SAAQ,GAAG;IACzD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,aAAa,CAAgB;gBAEzB,OAAO,EAAE,wBAAwB,EAAE,aAAa,GAAE,aAAkC;IAOhG,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAK3B,UAAU,IAAI,IAAI;IAK3B,OAAO,CAAC,aAAa;CAyBrB"}
@@ -1,6 +1,5 @@
1
1
  import { Box, Markdown, Spacer, Text } from "@gsd/pi-tui";
2
2
  import { getMarkdownTheme, theme } from "../theme/theme.js";
3
- import { editorKey } from "./keybinding-hints.js";
4
3
  /**
5
4
  * Component that renders a compaction message with collapsed/expanded state.
6
5
  * Uses same background color as custom messages for visual consistency.
@@ -34,9 +33,7 @@ export class CompactionSummaryMessageComponent extends Box {
34
33
  }));
35
34
  }
36
35
  else {
37
- this.addChild(new Text(theme.fg("customMessageText", `Compacted from ${tokenStr} tokens (`) +
38
- theme.fg("dim", editorKey("expandTools")) +
39
- theme.fg("customMessageText", " to expand)"), 0, 0));
36
+ this.addChild(new Text(theme.fg("customMessageText", `Compacted from ${tokenStr} tokens`), 0, 0));
40
37
  }
41
38
  }
42
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"compaction-summary-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/compaction-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAsB,MAAM,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAE9E,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;GAGG;AACH,MAAM,OAAO,iCAAkC,SAAQ,GAAG;IAKzD,YAAY,OAAiC,EAAE,gBAA+B,gBAAgB,EAAE;QAC/F,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,CAAC;QAL5C,aAAQ,GAAG,KAAK,CAAC;QAMxB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAED,WAAW,CAAC,QAAiB;QAC5B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAEQ,UAAU;QAClB,KAAK,CAAC,UAAU,EAAE,CAAC;QACnB,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAEO,aAAa;QACpB,IAAI,CAAC,KAAK,EAAE,CAAC;QAEb,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;QAC5D,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,oBAAoB,EAAE,6BAA6B,CAAC,CAAC;QAC5E,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACrC,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,MAAM,GAAG,oBAAoB,QAAQ,eAAe,CAAC;YAC3D,IAAI,CAAC,QAAQ,CACZ,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE;gBACrE,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,IAAI,CAAC;aAC5D,CAAC,CACF,CAAC;QACH,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,QAAQ,CACZ,IAAI,IAAI,CACP,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,kBAAkB,QAAQ,WAAW,CAAC;gBACnE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,aAAa,CAAC,CAAC;gBACzC,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,aAAa,CAAC,EAC7C,CAAC,EACD,CAAC,CACD,CACD,CAAC;QACH,CAAC;IACF,CAAC;CACD","sourcesContent":["import { Box, Markdown, type MarkdownTheme, Spacer, Text } from \"@gsd/pi-tui\";\nimport type { CompactionSummaryMessage } from \"../../../core/messages.js\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.js\";\nimport { editorKey } from \"./keybinding-hints.js\";\n\n/**\n * Component that renders a compaction message with collapsed/expanded state.\n * Uses same background color as custom messages for visual consistency.\n */\nexport class CompactionSummaryMessageComponent extends Box {\n\tprivate expanded = false;\n\tprivate message: CompactionSummaryMessage;\n\tprivate markdownTheme: MarkdownTheme;\n\n\tconstructor(message: CompactionSummaryMessage, markdownTheme: MarkdownTheme = getMarkdownTheme()) {\n\t\tsuper(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\t\tthis.message = message;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.clear();\n\n\t\tconst tokenStr = this.message.tokensBefore.toLocaleString();\n\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[compaction]\\x1b[22m`);\n\t\tthis.addChild(new Text(label, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (this.expanded) {\n\t\t\tconst header = `**Compacted from ${tokenStr} tokens**\\n\\n`;\n\t\t\tthis.addChild(\n\t\t\t\tnew Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\"customMessageText\", `Compacted from ${tokenStr} tokens (`) +\n\t\t\t\t\t\ttheme.fg(\"dim\", editorKey(\"expandTools\")) +\n\t\t\t\t\t\ttheme.fg(\"customMessageText\", \" to expand)\"),\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"compaction-summary-message.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/compaction-summary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAsB,MAAM,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAE9E,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAG5D;;;GAGG;AACH,MAAM,OAAO,iCAAkC,SAAQ,GAAG;IAKzD,YAAY,OAAiC,EAAE,gBAA+B,gBAAgB,EAAE;QAC/F,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,CAAC;QAL5C,aAAQ,GAAG,KAAK,CAAC;QAMxB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAED,WAAW,CAAC,QAAiB;QAC5B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAEQ,UAAU;QAClB,KAAK,CAAC,UAAU,EAAE,CAAC;QACnB,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAEO,aAAa;QACpB,IAAI,CAAC,KAAK,EAAE,CAAC;QAEb,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;QAC5D,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,oBAAoB,EAAE,6BAA6B,CAAC,CAAC;QAC5E,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACrC,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,MAAM,GAAG,oBAAoB,QAAQ,eAAe,CAAC;YAC3D,IAAI,CAAC,QAAQ,CACZ,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE;gBACrE,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,IAAI,CAAC;aAC5D,CAAC,CACF,CAAC;QACH,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,QAAQ,CACZ,IAAI,IAAI,CACP,KAAK,CAAC,EAAE,CAAC,mBAAmB,EAAE,kBAAkB,QAAQ,SAAS,CAAC,EAClE,CAAC,EACD,CAAC,CACD,CACD,CAAC;QACH,CAAC;IACF,CAAC;CACD","sourcesContent":["import { Box, Markdown, type MarkdownTheme, Spacer, Text } from \"@gsd/pi-tui\";\nimport type { CompactionSummaryMessage } from \"../../../core/messages.js\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.js\";\nimport { editorKey } from \"./keybinding-hints.js\";\n\n/**\n * Component that renders a compaction message with collapsed/expanded state.\n * Uses same background color as custom messages for visual consistency.\n */\nexport class CompactionSummaryMessageComponent extends Box {\n\tprivate expanded = false;\n\tprivate message: CompactionSummaryMessage;\n\tprivate markdownTheme: MarkdownTheme;\n\n\tconstructor(message: CompactionSummaryMessage, markdownTheme: MarkdownTheme = getMarkdownTheme()) {\n\t\tsuper(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\t\tthis.message = message;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.clear();\n\n\t\tconst tokenStr = this.message.tokensBefore.toLocaleString();\n\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[compaction]\\x1b[22m`);\n\t\tthis.addChild(new Text(label, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (this.expanded) {\n\t\t\tconst header = `**Compacted from ${tokenStr} tokens**\\n\\n`;\n\t\t\tthis.addChild(\n\t\t\t\tnew Markdown(header + this.message.summary, 0, 0, this.markdownTheme, {\n\t\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\"customMessageText\", `Compacted from ${tokenStr} tokens`),\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Embedded PTY terminal for user-triggered bash commands.
3
+ * Renders a framed terminal surface and forwards keystrokes to a PTY handle.
4
+ */
5
+ import { type Focusable, type TUI } from "@gsd/pi-tui";
6
+ import type { PtyExecutionHandle } from "../../../core/pty-executor.js";
7
+ type ToolOutputMode = "minimal" | "normal";
8
+ export declare class EmbeddedTerminalComponent implements Focusable {
9
+ focused: boolean;
10
+ private command;
11
+ private status;
12
+ private exitCode;
13
+ private focusKeyLabel;
14
+ private renderedLines;
15
+ private rawOutput;
16
+ private terminal;
17
+ private terminalWriteChain;
18
+ private handle?;
19
+ private releaseFocus?;
20
+ private statusOverride?;
21
+ constructor(command: string, _ui: TUI, _renderMode: ToolOutputMode, focusKeyLabel: string, _excludeFromContext?: boolean);
22
+ setHandle(handle: PtyExecutionHandle, releaseFocus: () => void): void;
23
+ setScreenText(text: string): void;
24
+ setStatusOverride(text: string | undefined): void;
25
+ resize(cols: number, rows: number): void;
26
+ setExpanded(_expanded: boolean): void;
27
+ setRenderMode(_mode: ToolOutputMode): void;
28
+ appendOutput(chunk: string): void;
29
+ setComplete(exitCode: number | undefined, cancelled: boolean): void;
30
+ getOutput(): string;
31
+ handleInput(data: string): void;
32
+ invalidate(): void;
33
+ render(width: number): string[];
34
+ private buildBodyLines;
35
+ private buildHeaderText;
36
+ private buildStatusText;
37
+ }
38
+ export {};
39
+ //# sourceMappingURL=embedded-terminal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedded-terminal.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/embedded-terminal.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAA8C,KAAK,SAAS,EAAE,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AAEnG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAIxE,KAAK,cAAc,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE3C,qBAAa,yBAA0B,YAAW,SAAS;IAChD,OAAO,UAAS;IAEvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAA6D;IAC3E,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,kBAAkB,CAAoC;IAC9D,OAAO,CAAC,MAAM,CAAC,CAAqB;IACpC,OAAO,CAAC,YAAY,CAAC,CAAa;IAClC,OAAO,CAAC,cAAc,CAAC,CAAS;gBAG5B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,GAAG,EACR,WAAW,EAAE,cAAc,EAC3B,aAAa,EAAE,MAAM,EACrB,mBAAmB,UAAQ;IAO/B,SAAS,CAAC,MAAM,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,IAAI,GAAG,IAAI;IAKrE,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKjC,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAIjD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAQxC,WAAW,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAIrC,aAAa,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAI1C,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAajC,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI;IASnE,SAAS,IAAI,MAAM;IAInB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAmD/B,UAAU,IAAI,IAAI;IAIlB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAqB/B,OAAO,CAAC,cAAc;IAgBtB,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,eAAe;CAiB1B"}
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Embedded PTY terminal for user-triggered bash commands.
3
+ * Renders a framed terminal surface and forwards keystrokes to a PTY handle.
4
+ */
5
+ import { decodeKittyPrintable, matchesKey, parseKey } from "@gsd/pi-tui";
6
+ import { truncateToWidth, visibleWidth } from "@gsd/pi-tui";
7
+ import { createHeadlessTerminal, snapshotTerminalLines } from "../../../utils/terminal-screen.js";
8
+ import { theme } from "../theme/theme.js";
9
+ export class EmbeddedTerminalComponent {
10
+ constructor(command, _ui, _renderMode, focusKeyLabel, _excludeFromContext = false) {
11
+ this.focused = false;
12
+ this.status = "running";
13
+ this.renderedLines = [];
14
+ this.rawOutput = "";
15
+ this.terminalWriteChain = Promise.resolve();
16
+ this.command = command;
17
+ this.focusKeyLabel = focusKeyLabel;
18
+ this.terminal = createHeadlessTerminal();
19
+ }
20
+ setHandle(handle, releaseFocus) {
21
+ this.handle = handle;
22
+ this.releaseFocus = releaseFocus;
23
+ }
24
+ setScreenText(text) {
25
+ this.rawOutput = text;
26
+ this.renderedLines = text ? text.split("\n") : [];
27
+ }
28
+ setStatusOverride(text) {
29
+ this.statusOverride = text;
30
+ }
31
+ resize(cols, rows) {
32
+ const safeCols = Math.max(20, cols);
33
+ const safeRows = Math.max(5, rows);
34
+ this.handle?.resize(safeCols, safeRows);
35
+ this.terminal.resize(safeCols, safeRows);
36
+ this.renderedLines = snapshotTerminalLines(this.terminal);
37
+ }
38
+ setExpanded(_expanded) {
39
+ // Interactive terminals are always rendered expanded for now.
40
+ }
41
+ setRenderMode(_mode) {
42
+ // Interactive terminals are always rendered expanded for now.
43
+ }
44
+ appendOutput(chunk) {
45
+ this.rawOutput += chunk;
46
+ this.terminalWriteChain = this.terminalWriteChain.then(() => new Promise((resolve) => {
47
+ this.terminal.write(chunk, () => {
48
+ this.renderedLines = snapshotTerminalLines(this.terminal);
49
+ resolve();
50
+ });
51
+ }));
52
+ }
53
+ setComplete(exitCode, cancelled) {
54
+ this.exitCode = exitCode;
55
+ this.status = cancelled
56
+ ? "cancelled"
57
+ : exitCode !== undefined && exitCode !== 0
58
+ ? "error"
59
+ : "complete";
60
+ }
61
+ getOutput() {
62
+ return this.rawOutput;
63
+ }
64
+ handleInput(data) {
65
+ if (matchesKey(data, "escape") || matchesKey(data, "tab")) {
66
+ this.releaseFocus?.();
67
+ return;
68
+ }
69
+ const kittyPrintable = decodeKittyPrintable(data);
70
+ if (kittyPrintable !== undefined) {
71
+ this.handle?.write(kittyPrintable);
72
+ return;
73
+ }
74
+ const key = parseKey(data);
75
+ switch (key) {
76
+ case "enter":
77
+ case "shift+enter":
78
+ this.handle?.write("\r");
79
+ return;
80
+ case "shift+tab":
81
+ case "tab":
82
+ this.handle?.write("\t");
83
+ return;
84
+ case "backspace":
85
+ case "shift+backspace":
86
+ this.handle?.write("\x7f");
87
+ return;
88
+ case "up":
89
+ this.handle?.write("\x1b[A");
90
+ return;
91
+ case "down":
92
+ this.handle?.write("\x1b[B");
93
+ return;
94
+ case "right":
95
+ this.handle?.write("\x1b[C");
96
+ return;
97
+ case "left":
98
+ this.handle?.write("\x1b[D");
99
+ return;
100
+ case "ctrl+c":
101
+ this.handle?.write("\x03");
102
+ return;
103
+ case "ctrl+d":
104
+ this.handle?.write("\x04");
105
+ return;
106
+ }
107
+ if (data.length === 1 && data >= " " && data !== "\x7f") {
108
+ this.handle?.write(data);
109
+ }
110
+ }
111
+ invalidate() {
112
+ // No-op; render reads directly from current state.
113
+ }
114
+ render(width) {
115
+ const innerWidth = Math.max(10, width - 2);
116
+ const frameColor = this.status === "error"
117
+ ? "error"
118
+ : this.focused
119
+ ? "success"
120
+ : "success";
121
+ const border = (text) => theme.fg(frameColor, text);
122
+ const lines = [];
123
+ lines.push(border(`╭${"─".repeat(innerWidth)}╮`));
124
+ for (const line of this.buildBodyLines(innerWidth)) {
125
+ const content = truncateToWidth(line, innerWidth, "", true);
126
+ lines.push(`${border("│")}${content}${border("│")}`);
127
+ }
128
+ lines.push(border(`╰${"─".repeat(innerWidth)}╯`));
129
+ return lines;
130
+ }
131
+ buildBodyLines(innerWidth) {
132
+ const body = [];
133
+ body.push(this.buildHeaderText(innerWidth));
134
+ body.push("");
135
+ if (this.renderedLines.length > 0) {
136
+ body.push(...this.renderedLines);
137
+ }
138
+ else if (this.status === "running") {
139
+ body.push(theme.fg("dim", "Terminal waiting for output…"));
140
+ }
141
+ body.push("");
142
+ body.push(this.buildStatusText(innerWidth));
143
+ return body;
144
+ }
145
+ buildHeaderText(innerWidth) {
146
+ const prefix = this.focused
147
+ ? theme.fg("success", theme.bold(" TERMINAL "))
148
+ : theme.fg("success", " terminal ");
149
+ const command = theme.bold(`$ ${this.command}`);
150
+ const hint = this.focused
151
+ ? theme.fg("muted", "Tab/Esc return · Shift+Tab sends Tab")
152
+ : theme.fg("muted", `${this.focusKeyLabel} focus`);
153
+ const left = `${prefix} ${command}`;
154
+ const leftWidth = visibleWidth(left);
155
+ const hintWidth = visibleWidth(hint);
156
+ if (leftWidth + 2 + hintWidth <= innerWidth) {
157
+ return left + " ".repeat(innerWidth - leftWidth - hintWidth) + hint;
158
+ }
159
+ return truncateToWidth(`${left} ${hint}`, innerWidth, "...");
160
+ }
161
+ buildStatusText(innerWidth) {
162
+ let statusText;
163
+ if (this.status === "running") {
164
+ statusText = this.statusOverride
165
+ ? this.statusOverride
166
+ : this.focused
167
+ ? theme.fg("success", theme.bold("INPUT CAPTURED")) + theme.fg("muted", " — typing goes to the terminal")
168
+ : theme.fg("muted", `Press ${this.focusKeyLabel} to focus this terminal`);
169
+ }
170
+ else if (this.status === "cancelled") {
171
+ statusText = theme.fg("warning", "(cancelled)");
172
+ }
173
+ else if (this.status === "error") {
174
+ statusText = theme.fg("error", `(exit ${this.exitCode})`);
175
+ }
176
+ else {
177
+ statusText = theme.fg("success", "(done)");
178
+ }
179
+ return truncateToWidth(statusText, innerWidth, "...");
180
+ }
181
+ }
182
+ //# sourceMappingURL=embedded-terminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedded-terminal.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/embedded-terminal.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Embedded PTY terminal for user-triggered bash commands.\n * Renders a framed terminal surface and forwards keystrokes to a PTY handle.\n */\n\nimport { decodeKittyPrintable, matchesKey, parseKey, type Focusable, type TUI } from \"@gsd/pi-tui\";\nimport { truncateToWidth, visibleWidth } from \"@gsd/pi-tui\";\nimport type { PtyExecutionHandle } from \"../../../core/pty-executor.js\";\nimport { createHeadlessTerminal, snapshotTerminalLines, type HeadlessTerminal } from \"../../../utils/terminal-screen.js\";\nimport { theme } from \"../theme/theme.js\";\n\ntype ToolOutputMode = \"minimal\" | \"normal\";\n\nexport class EmbeddedTerminalComponent implements Focusable {\n public focused = false;\n\n private command: string;\n private status: \"running\" | \"complete\" | \"cancelled\" | \"error\" = \"running\";\n private exitCode: number | undefined;\n private focusKeyLabel: string;\n private renderedLines: string[] = [];\n private rawOutput = \"\";\n private terminal: HeadlessTerminal;\n private terminalWriteChain: Promise<void> = Promise.resolve();\n private handle?: PtyExecutionHandle;\n private releaseFocus?: () => void;\n private statusOverride?: string;\n\n constructor(\n command: string,\n _ui: TUI,\n _renderMode: ToolOutputMode,\n focusKeyLabel: string,\n _excludeFromContext = false,\n ) {\n this.command = command;\n this.focusKeyLabel = focusKeyLabel;\n this.terminal = createHeadlessTerminal();\n }\n\n setHandle(handle: PtyExecutionHandle, releaseFocus: () => void): void {\n this.handle = handle;\n this.releaseFocus = releaseFocus;\n }\n\n setScreenText(text: string): void {\n this.rawOutput = text;\n this.renderedLines = text ? text.split(\"\\n\") : [];\n }\n\n setStatusOverride(text: string | undefined): void {\n this.statusOverride = text;\n }\n\n resize(cols: number, rows: number): void {\n const safeCols = Math.max(20, cols);\n const safeRows = Math.max(5, rows);\n this.handle?.resize(safeCols, safeRows);\n this.terminal.resize(safeCols, safeRows);\n this.renderedLines = snapshotTerminalLines(this.terminal);\n }\n\n setExpanded(_expanded: boolean): void {\n // Interactive terminals are always rendered expanded for now.\n }\n\n setRenderMode(_mode: ToolOutputMode): void {\n // Interactive terminals are always rendered expanded for now.\n }\n\n appendOutput(chunk: string): void {\n this.rawOutput += chunk;\n this.terminalWriteChain = this.terminalWriteChain.then(\n () =>\n new Promise<void>((resolve) => {\n this.terminal.write(chunk, () => {\n this.renderedLines = snapshotTerminalLines(this.terminal);\n resolve();\n });\n }),\n );\n }\n\n setComplete(exitCode: number | undefined, cancelled: boolean): void {\n this.exitCode = exitCode;\n this.status = cancelled\n ? \"cancelled\"\n : exitCode !== undefined && exitCode !== 0\n ? \"error\"\n : \"complete\";\n }\n\n getOutput(): string {\n return this.rawOutput;\n }\n\n handleInput(data: string): void {\n if (matchesKey(data, \"escape\") || matchesKey(data, \"tab\")) {\n this.releaseFocus?.();\n return;\n }\n\n const kittyPrintable = decodeKittyPrintable(data);\n if (kittyPrintable !== undefined) {\n this.handle?.write(kittyPrintable);\n return;\n }\n\n const key = parseKey(data);\n switch (key) {\n case \"enter\":\n case \"shift+enter\":\n this.handle?.write(\"\\r\");\n return;\n case \"shift+tab\":\n case \"tab\":\n this.handle?.write(\"\\t\");\n return;\n case \"backspace\":\n case \"shift+backspace\":\n this.handle?.write(\"\\x7f\");\n return;\n case \"up\":\n this.handle?.write(\"\\x1b[A\");\n return;\n case \"down\":\n this.handle?.write(\"\\x1b[B\");\n return;\n case \"right\":\n this.handle?.write(\"\\x1b[C\");\n return;\n case \"left\":\n this.handle?.write(\"\\x1b[D\");\n return;\n case \"ctrl+c\":\n this.handle?.write(\"\\x03\");\n return;\n case \"ctrl+d\":\n this.handle?.write(\"\\x04\");\n return;\n }\n\n if (data.length === 1 && data >= \" \" && data !== \"\\x7f\") {\n this.handle?.write(data);\n }\n }\n\n invalidate(): void {\n // No-op; render reads directly from current state.\n }\n\n render(width: number): string[] {\n const innerWidth = Math.max(10, width - 2);\n const frameColor = this.status === \"error\"\n ? \"error\"\n : this.focused\n ? \"success\"\n : \"success\";\n const border = (text: string) => theme.fg(frameColor, text);\n\n const lines: string[] = [];\n lines.push(border(`╭${\"─\".repeat(innerWidth)}╮`));\n\n for (const line of this.buildBodyLines(innerWidth)) {\n const content = truncateToWidth(line, innerWidth, \"\", true);\n lines.push(`${border(\"│\")}${content}${border(\"│\")}`);\n }\n\n lines.push(border(`╰${\"─\".repeat(innerWidth)}╯`));\n return lines;\n }\n\n private buildBodyLines(innerWidth: number): string[] {\n const body: string[] = [];\n body.push(this.buildHeaderText(innerWidth));\n body.push(\"\");\n\n if (this.renderedLines.length > 0) {\n body.push(...this.renderedLines);\n } else if (this.status === \"running\") {\n body.push(theme.fg(\"dim\", \"Terminal waiting for output…\"));\n }\n\n body.push(\"\");\n body.push(this.buildStatusText(innerWidth));\n return body;\n }\n\n private buildHeaderText(innerWidth: number): string {\n const prefix = this.focused\n ? theme.fg(\"success\", theme.bold(\" TERMINAL \"))\n : theme.fg(\"success\", \" terminal \");\n const command = theme.bold(`$ ${this.command}`);\n const hint = this.focused\n ? theme.fg(\"muted\", \"Tab/Esc return · Shift+Tab sends Tab\")\n : theme.fg(\"muted\", `${this.focusKeyLabel} focus`);\n\n const left = `${prefix} ${command}`;\n const leftWidth = visibleWidth(left);\n const hintWidth = visibleWidth(hint);\n if (leftWidth + 2 + hintWidth <= innerWidth) {\n return left + \" \".repeat(innerWidth - leftWidth - hintWidth) + hint;\n }\n return truncateToWidth(`${left} ${hint}`, innerWidth, \"...\");\n }\n\n private buildStatusText(innerWidth: number): string {\n let statusText: string;\n if (this.status === \"running\") {\n statusText = this.statusOverride\n ? this.statusOverride\n : this.focused\n ? theme.fg(\"success\", theme.bold(\"INPUT CAPTURED\")) + theme.fg(\"muted\", \" — typing goes to the terminal\")\n : theme.fg(\"muted\", `Press ${this.focusKeyLabel} to focus this terminal`);\n } else if (this.status === \"cancelled\") {\n statusText = theme.fg(\"warning\", \"(cancelled)\");\n } else if (this.status === \"error\") {\n statusText = theme.fg(\"error\", `(exit ${this.exitCode})`);\n } else {\n statusText = theme.fg(\"success\", \"(done)\");\n }\n return truncateToWidth(statusText, innerWidth, \"...\");\n }\n}\n"]}