openhorse 0.2.21 → 0.2.23

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 (263) hide show
  1. package/dist/cli.js +25 -0
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/index.d.ts.map +1 -1
  4. package/dist/commands/index.js +189 -49
  5. package/dist/commands/index.js.map +1 -1
  6. package/dist/commands/parser.d.ts.map +1 -1
  7. package/dist/commands/parser.js +8 -3
  8. package/dist/commands/parser.js.map +1 -1
  9. package/dist/commands/types.d.ts +2 -0
  10. package/dist/commands/types.d.ts.map +1 -1
  11. package/dist/commands/types.js.map +1 -1
  12. package/dist/core/cost-tracker.d.ts +45 -5
  13. package/dist/core/cost-tracker.d.ts.map +1 -1
  14. package/dist/core/cost-tracker.js +78 -13
  15. package/dist/core/cost-tracker.js.map +1 -1
  16. package/dist/framework/index.d.ts +1 -1
  17. package/dist/framework/index.d.ts.map +1 -1
  18. package/dist/framework/index.js.map +1 -1
  19. package/dist/framework/query.d.ts +25 -0
  20. package/dist/framework/query.d.ts.map +1 -1
  21. package/dist/framework/query.js +196 -49
  22. package/dist/framework/query.js.map +1 -1
  23. package/dist/framework/store.d.ts +6 -1
  24. package/dist/framework/store.d.ts.map +1 -1
  25. package/dist/framework/store.js +10 -1
  26. package/dist/framework/store.js.map +1 -1
  27. package/dist/harness/capsule.d.ts +1 -0
  28. package/dist/harness/capsule.d.ts.map +1 -1
  29. package/dist/harness/capsule.js +38 -9
  30. package/dist/harness/capsule.js.map +1 -1
  31. package/dist/harness/contract.d.ts +2 -0
  32. package/dist/harness/contract.d.ts.map +1 -1
  33. package/dist/harness/contract.js +78 -14
  34. package/dist/harness/contract.js.map +1 -1
  35. package/dist/harness/index.d.ts +2 -2
  36. package/dist/harness/index.d.ts.map +1 -1
  37. package/dist/harness/index.js +4 -1
  38. package/dist/harness/index.js.map +1 -1
  39. package/dist/harness/ledger.d.ts.map +1 -1
  40. package/dist/harness/ledger.js +6 -2
  41. package/dist/harness/ledger.js.map +1 -1
  42. package/dist/harness/state.d.ts.map +1 -1
  43. package/dist/harness/state.js +37 -7
  44. package/dist/harness/state.js.map +1 -1
  45. package/dist/index.d.ts +2 -1
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/ink-ui/components/StatusLine.d.ts.map +1 -1
  48. package/dist/ink-ui/components/StatusLine.js +0 -2
  49. package/dist/ink-ui/components/StatusLine.js.map +1 -1
  50. package/dist/ink-ui/screens/ReplScreen.d.ts.map +1 -1
  51. package/dist/ink-ui/screens/ReplScreen.js +12 -5
  52. package/dist/ink-ui/screens/ReplScreen.js.map +1 -1
  53. package/dist/runtime/agent-runtime-controller.d.ts.map +1 -1
  54. package/dist/runtime/agent-runtime-controller.js +11 -1
  55. package/dist/runtime/agent-runtime-controller.js.map +1 -1
  56. package/dist/runtime/aggregate-tool-presenter.d.ts +13 -0
  57. package/dist/runtime/aggregate-tool-presenter.d.ts.map +1 -0
  58. package/dist/runtime/aggregate-tool-presenter.js +44 -0
  59. package/dist/runtime/aggregate-tool-presenter.js.map +1 -0
  60. package/dist/runtime/chat-controller.d.ts +9 -2
  61. package/dist/runtime/chat-controller.d.ts.map +1 -1
  62. package/dist/runtime/chat-controller.js +345 -90
  63. package/dist/runtime/chat-controller.js.map +1 -1
  64. package/dist/runtime/rich-text/ansi-parser.d.ts +1 -1
  65. package/dist/runtime/rich-text/ansi-parser.d.ts.map +1 -1
  66. package/dist/runtime/rich-text/ansi-parser.js +93 -55
  67. package/dist/runtime/rich-text/ansi-parser.js.map +1 -1
  68. package/dist/runtime/rich-text/layout.d.ts +2 -11
  69. package/dist/runtime/rich-text/layout.d.ts.map +1 -1
  70. package/dist/runtime/rich-text/layout.js +280 -245
  71. package/dist/runtime/rich-text/layout.js.map +1 -1
  72. package/dist/runtime/rich-text/markdown-parser.js +31 -24
  73. package/dist/runtime/rich-text/markdown-parser.js.map +1 -1
  74. package/dist/runtime/rich-text/types.d.ts +1 -1
  75. package/dist/runtime/rich-text/types.d.ts.map +1 -1
  76. package/dist/runtime/subagents/production.d.ts.map +1 -1
  77. package/dist/runtime/subagents/production.js +28 -3
  78. package/dist/runtime/subagents/production.js.map +1 -1
  79. package/dist/runtime/subagents/result-parser.d.ts.map +1 -1
  80. package/dist/runtime/subagents/result-parser.js +54 -40
  81. package/dist/runtime/subagents/result-parser.js.map +1 -1
  82. package/dist/runtime/subagents/types.d.ts +2 -0
  83. package/dist/runtime/subagents/types.d.ts.map +1 -1
  84. package/dist/runtime/subagents/types.js +5 -1
  85. package/dist/runtime/subagents/types.js.map +1 -1
  86. package/dist/runtime/tool-detail-repository.d.ts +45 -0
  87. package/dist/runtime/tool-detail-repository.d.ts.map +1 -0
  88. package/dist/runtime/tool-detail-repository.js +131 -0
  89. package/dist/runtime/tool-detail-repository.js.map +1 -0
  90. package/dist/runtime/tool-output-presentation.d.ts +89 -0
  91. package/dist/runtime/tool-output-presentation.d.ts.map +1 -0
  92. package/dist/runtime/tool-output-presentation.js +329 -0
  93. package/dist/runtime/tool-output-presentation.js.map +1 -0
  94. package/dist/runtime/ui-events.d.ts +17 -0
  95. package/dist/runtime/ui-events.d.ts.map +1 -1
  96. package/dist/runtime/ui-events.js.map +1 -1
  97. package/dist/runtime/ui-view-model.d.ts +9 -0
  98. package/dist/runtime/ui-view-model.d.ts.map +1 -1
  99. package/dist/runtime/ui-view-model.js +59 -37
  100. package/dist/runtime/ui-view-model.js.map +1 -1
  101. package/dist/services/compact/auto-compact.d.ts +15 -2
  102. package/dist/services/compact/auto-compact.d.ts.map +1 -1
  103. package/dist/services/compact/auto-compact.js +56 -24
  104. package/dist/services/compact/auto-compact.js.map +1 -1
  105. package/dist/services/compact/compact.d.ts +2 -0
  106. package/dist/services/compact/compact.d.ts.map +1 -1
  107. package/dist/services/compact/compact.js +22 -5
  108. package/dist/services/compact/compact.js.map +1 -1
  109. package/dist/services/compact/coordinator.d.ts +26 -0
  110. package/dist/services/compact/coordinator.d.ts.map +1 -0
  111. package/dist/services/compact/coordinator.js +44 -0
  112. package/dist/services/compact/coordinator.js.map +1 -0
  113. package/dist/services/compact/index.d.ts +1 -0
  114. package/dist/services/compact/index.d.ts.map +1 -1
  115. package/dist/services/compact/index.js +3 -1
  116. package/dist/services/compact/index.js.map +1 -1
  117. package/dist/services/compact/summary-generator.d.ts +6 -2
  118. package/dist/services/compact/summary-generator.d.ts.map +1 -1
  119. package/dist/services/compact/summary-generator.js +73 -31
  120. package/dist/services/compact/summary-generator.js.map +1 -1
  121. package/dist/services/config-dir.d.ts +11 -1
  122. package/dist/services/config-dir.d.ts.map +1 -1
  123. package/dist/services/config-dir.js +19 -2
  124. package/dist/services/config-dir.js.map +1 -1
  125. package/dist/services/config.d.ts +4 -2
  126. package/dist/services/config.d.ts.map +1 -1
  127. package/dist/services/config.js +40 -0
  128. package/dist/services/config.js.map +1 -1
  129. package/dist/services/doctor.d.ts +2 -0
  130. package/dist/services/doctor.d.ts.map +1 -1
  131. package/dist/services/doctor.js +8 -1
  132. package/dist/services/doctor.js.map +1 -1
  133. package/dist/services/global-config.d.ts +10 -0
  134. package/dist/services/global-config.d.ts.map +1 -1
  135. package/dist/services/global-config.js.map +1 -1
  136. package/dist/services/llm.d.ts +21 -4
  137. package/dist/services/llm.d.ts.map +1 -1
  138. package/dist/services/llm.js +66 -8
  139. package/dist/services/llm.js.map +1 -1
  140. package/dist/services/model-context.d.ts +36 -0
  141. package/dist/services/model-context.d.ts.map +1 -1
  142. package/dist/services/model-context.js +245 -32
  143. package/dist/services/model-context.js.map +1 -1
  144. package/dist/services/redaction.js +1 -1
  145. package/dist/services/redaction.js.map +1 -1
  146. package/dist/services/session-storage.d.ts +42 -1
  147. package/dist/services/session-storage.d.ts.map +1 -1
  148. package/dist/services/session-storage.js +175 -54
  149. package/dist/services/session-storage.js.map +1 -1
  150. package/dist/services/storage-maintenance.d.ts.map +1 -1
  151. package/dist/services/storage-maintenance.js +3 -2
  152. package/dist/services/storage-maintenance.js.map +1 -1
  153. package/dist/services/usage-state.d.ts +55 -5
  154. package/dist/services/usage-state.d.ts.map +1 -1
  155. package/dist/services/usage-state.js +185 -59
  156. package/dist/services/usage-state.js.map +1 -1
  157. package/dist/services/verification-profile.d.ts.map +1 -1
  158. package/dist/services/verification-profile.js +3 -2
  159. package/dist/services/verification-profile.js.map +1 -1
  160. package/dist/services/workspace-diff.d.ts.map +1 -1
  161. package/dist/services/workspace-diff.js +34 -3
  162. package/dist/services/workspace-diff.js.map +1 -1
  163. package/dist/services/yaml-config.js +1 -1
  164. package/dist/skills/runtime.d.ts +9 -5
  165. package/dist/skills/runtime.d.ts.map +1 -1
  166. package/dist/skills/runtime.js +157 -12
  167. package/dist/skills/runtime.js.map +1 -1
  168. package/dist/terminal-ui/editor.d.ts.map +1 -1
  169. package/dist/terminal-ui/editor.js +14 -3
  170. package/dist/terminal-ui/editor.js.map +1 -1
  171. package/dist/terminal-ui/launch.d.ts +21 -0
  172. package/dist/terminal-ui/launch.d.ts.map +1 -1
  173. package/dist/terminal-ui/launch.js +203 -45
  174. package/dist/terminal-ui/launch.js.map +1 -1
  175. package/dist/terminal-ui/output-queue.d.ts +43 -0
  176. package/dist/terminal-ui/output-queue.d.ts.map +1 -0
  177. package/dist/terminal-ui/output-queue.js +139 -0
  178. package/dist/terminal-ui/output-queue.js.map +1 -0
  179. package/dist/terminal-ui/raw-editor.d.ts +42 -0
  180. package/dist/terminal-ui/raw-editor.d.ts.map +1 -1
  181. package/dist/terminal-ui/raw-editor.js +337 -41
  182. package/dist/terminal-ui/raw-editor.js.map +1 -1
  183. package/dist/tools/bash_security.d.ts.map +1 -1
  184. package/dist/tools/bash_security.js +14 -5
  185. package/dist/tools/bash_security.js.map +1 -1
  186. package/dist/tools/index.d.ts.map +1 -1
  187. package/dist/tools/index.js +176 -73
  188. package/dist/tools/index.js.map +1 -1
  189. package/dist/tools/plan.d.ts.map +1 -1
  190. package/dist/tools/plan.js +7 -0
  191. package/dist/tools/plan.js.map +1 -1
  192. package/dist/tools/web.d.ts +10 -0
  193. package/dist/tools/web.d.ts.map +1 -1
  194. package/dist/tools/web.js +81 -1
  195. package/dist/tools/web.js.map +1 -1
  196. package/dist/tui-core/input-parser.d.ts +9 -2
  197. package/dist/tui-core/input-parser.d.ts.map +1 -1
  198. package/dist/tui-core/input-parser.js +57 -3
  199. package/dist/tui-core/input-parser.js.map +1 -1
  200. package/dist/tui-core/style.d.ts +16 -0
  201. package/dist/tui-core/style.d.ts.map +1 -1
  202. package/dist/tui-core/style.js +22 -1
  203. package/dist/tui-core/style.js.map +1 -1
  204. package/dist/tui-ui/inline-surface.d.ts +69 -12
  205. package/dist/tui-ui/inline-surface.d.ts.map +1 -1
  206. package/dist/tui-ui/inline-surface.js +366 -94
  207. package/dist/tui-ui/inline-surface.js.map +1 -1
  208. package/dist/tui-ui/input-ownership.d.ts +46 -0
  209. package/dist/tui-ui/input-ownership.d.ts.map +1 -0
  210. package/dist/tui-ui/input-ownership.js +74 -0
  211. package/dist/tui-ui/input-ownership.js.map +1 -0
  212. package/dist/tui-ui/launch.d.ts +2 -0
  213. package/dist/tui-ui/launch.d.ts.map +1 -1
  214. package/dist/tui-ui/launch.js +289 -43
  215. package/dist/tui-ui/launch.js.map +1 -1
  216. package/dist/tui-ui/layout.d.ts +52 -2
  217. package/dist/tui-ui/layout.d.ts.map +1 -1
  218. package/dist/tui-ui/layout.js +230 -76
  219. package/dist/tui-ui/layout.js.map +1 -1
  220. package/dist/tui-ui/runner.d.ts +101 -8
  221. package/dist/tui-ui/runner.d.ts.map +1 -1
  222. package/dist/tui-ui/runner.js +843 -51
  223. package/dist/tui-ui/runner.js.map +1 -1
  224. package/dist/tui-ui/state.d.ts +70 -4
  225. package/dist/tui-ui/state.d.ts.map +1 -1
  226. package/dist/tui-ui/state.js +251 -20
  227. package/dist/tui-ui/state.js.map +1 -1
  228. package/dist/tui-ui/theme-profile.d.ts +25 -0
  229. package/dist/tui-ui/theme-profile.d.ts.map +1 -0
  230. package/dist/tui-ui/theme-profile.js +130 -0
  231. package/dist/tui-ui/theme-profile.js.map +1 -0
  232. package/dist/tui-ui/theme.d.ts +13 -0
  233. package/dist/tui-ui/theme.d.ts.map +1 -0
  234. package/dist/tui-ui/theme.js +20 -0
  235. package/dist/tui-ui/theme.js.map +1 -0
  236. package/dist/tui-ui/transcript-cache.d.ts +5 -3
  237. package/dist/tui-ui/transcript-cache.d.ts.map +1 -1
  238. package/dist/tui-ui/transcript-cache.js +16 -9
  239. package/dist/tui-ui/transcript-cache.js.map +1 -1
  240. package/dist/tui-ui/transcript-inspector-layout.d.ts +9 -0
  241. package/dist/tui-ui/transcript-inspector-layout.d.ts.map +1 -0
  242. package/dist/tui-ui/transcript-inspector-layout.js +97 -0
  243. package/dist/tui-ui/transcript-inspector-layout.js.map +1 -0
  244. package/dist/tui-ui/transcript-inspector-surface.d.ts +18 -0
  245. package/dist/tui-ui/transcript-inspector-surface.d.ts.map +1 -0
  246. package/dist/tui-ui/transcript-inspector-surface.js +88 -0
  247. package/dist/tui-ui/transcript-inspector-surface.js.map +1 -0
  248. package/dist/tui-ui/transcript-inspector.d.ts +35 -0
  249. package/dist/tui-ui/transcript-inspector.d.ts.map +1 -0
  250. package/dist/tui-ui/transcript-inspector.js +128 -0
  251. package/dist/tui-ui/transcript-inspector.js.map +1 -0
  252. package/dist/tui-ui/transcript-layout.d.ts +22 -0
  253. package/dist/tui-ui/transcript-layout.d.ts.map +1 -0
  254. package/dist/tui-ui/transcript-layout.js +439 -0
  255. package/dist/tui-ui/transcript-layout.js.map +1 -0
  256. package/dist/ui/status-bar.d.ts +1 -1
  257. package/dist/ui/status-bar.d.ts.map +1 -1
  258. package/dist/ui/status-bar.js +2 -15
  259. package/dist/ui/status-bar.js.map +1 -1
  260. package/dist/ui-v2/components/shell.d.ts.map +1 -1
  261. package/dist/ui-v2/components/shell.js +0 -8
  262. package/dist/ui-v2/components/shell.js.map +1 -1
  263. package/package.json +1 -1
@@ -21,6 +21,7 @@ export declare function formatTerminalStatusMessage(message: string, width?: num
21
21
  export declare function formatTerminalSessionRestored(event: RuntimeSessionRestoredEvent): string;
22
22
  export interface TerminalWriter {
23
23
  write(text: string): void;
24
+ writeAsync?: (text: string) => Promise<boolean>;
24
25
  }
25
26
  export declare function visibleLength(text: string): number;
26
27
  export declare function terminalContentWidth(fallback?: number): number;
@@ -36,6 +37,7 @@ export declare class TerminalEventSink implements UiEventSink {
36
37
  private readonly entries;
37
38
  private readonly printedContent;
38
39
  private readonly pendingAssistantOutput;
40
+ private readonly finalizedEntryIds;
39
41
  private idCounter;
40
42
  private pendingPicker;
41
43
  private pickerOffset;
@@ -48,6 +50,9 @@ export declare class TerminalEventSink implements UiEventSink {
48
50
  * future timeline rendering.
49
51
  */
50
52
  private readonly subtaskTimeline;
53
+ private static readonly MAX_FINALIZED_METADATA;
54
+ private static readonly MAX_PRINTED_CONTENT;
55
+ private static readonly MAX_SUBTASK_TIMELINE;
51
56
  constructor(runtime: OpenHorseUiRuntime, writer?: TerminalWriter);
52
57
  append(entry: TranscriptAppendEntry): string;
53
58
  update(id: string, patch: Partial<Omit<TranscriptEntry, 'id'>>): void;
@@ -66,6 +71,7 @@ export declare class TerminalEventSink implements UiEventSink {
66
71
  private moveSessionPickerPage;
67
72
  private printEntry;
68
73
  private printAssistantDelta;
74
+ private writeWithAcknowledgement;
69
75
  /**
70
76
  * R8: consume the typed subagent event into the shared timeline view-model.
71
77
  * Does not print (the chat-controller transcript summary already drives
@@ -74,8 +80,23 @@ export declare class TerminalEventSink implements UiEventSink {
74
80
  subtaskEvent(event: RuntimeSubtaskEvent): void;
75
81
  /** R8: read-only access to the typed subagent timeline (for parity tests). */
76
82
  getSubtaskTimeline(): SubtaskTimelineEntry[];
83
+ /**
84
+ * After finalize, the entry content is in native scrollback.
85
+ * Replace the full body with a lightweight marker so memory doesn't grow
86
+ * with scrollback length.
87
+ */
88
+ private releaseEntryBody;
89
+ /**
90
+ * Evict oldest entries from a Map when it exceeds the configured limit.
91
+ * Uses Map's insertion-order iteration — oldest entries are evicted first.
92
+ * Mirrors evictOldest in session-storage.ts; kept private to avoid a shared
93
+ * dependency on session-storage internals.
94
+ */
95
+ private evictIfNeeded;
77
96
  }
78
97
  export declare function renderTerminalBanner(runtime: OpenHorseUiRuntime): string;
98
+ export declare function renderTerminalContextStatus(runtime: OpenHorseUiRuntime): string;
99
+ export declare function promptText(runtime: OpenHorseUiRuntime): string;
79
100
  export declare function formatTerminalPermissionPrompt(request: ToolPermissionRequest, cwd: string): string;
80
101
  export declare function parseEditInput(input: string): {
81
102
  isEdit: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"launch.d.ts","sourceRoot":"","sources":["../../src/terminal-ui/launch.ts"],"names":[],"mappings":"AAGA,OAAO,EAA0B,KAAK,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAGrG,OAAO,EASL,KAAK,iBAAiB,EAEtB,KAAK,oBAAoB,EAC1B,MAAM,0BAA0B,CAAC;AAMlC,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,2BAA2B,EAC3B,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,eAAe,EACf,qBAAqB,EACrB,WAAW,EACZ,MAAM,sBAAsB,CAAC;AAY9B,MAAM,MAAM,8BAA8B,GACtC;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AA8BvC,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,oBAAoB,GAC5B,8BAA8B,CAiDhC;AAwBD,MAAM,MAAM,kBAAkB,GAAG,OAAO,sBAAsB,EAAE,UAAU,CAAC;AAc3E,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,OAAO,sBAAsB,EAAE,UAAU,GAAG,MAAM,CAQ7H;AAYD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,kBAAkB,CA0B3E;AAMD,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,EACf,KAAK,SAA4B,GAChC,MAAM,CAER;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,2BAA2B,GAAG,MAAM,CAqBxF;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAUD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,SAAK,GAAG,MAAM,CAU1D;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAW3E;AAWD,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CASnF;AAED,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,iBAAiB,EACvB,KAAK,SAA4B,GAChC,MAAM,CAyBR;AAED,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,KAAK,SAA4B,GAChC,MAAM,CAQR;AAaD,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,kBAAkB,EAC3B,KAAK,SAA4B,GAChC,MAAM,CAKR;AAED,wBAAgB,kCAAkC,CAChD,SAAS,EAAE,kBAAkB,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,EACnD,SAAS,EAAE,MAAM,EACjB,KAAK,SAA4B,GAChC,MAAM,CAmBR;AAED,qBAAa,iBAAkB,YAAW,WAAW;IAkBjD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAlBzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;IAC9D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA6B;IAC5D,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAA6B;IACpE,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,aAAa,CAAqC;IAC1D,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,kBAAkB,CAAmC;IAC7D,OAAO,CAAC,iBAAiB,CAAM;IAC/B;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA2C;gBAGxD,OAAO,EAAE,kBAAkB,EAC3B,MAAM,GAAE,cAA2C;IAGtE,MAAM,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM;IAa5C,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI;IAQrE,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI;IAQxE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAKxB,iBAAiB,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI;IAgBnD,eAAe,IAAI,IAAI;IAOvB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAOhC,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI;IAMtD,eAAe,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI;IAclD,eAAe,CAAC,KAAK,EAAE,2BAA2B,GAAG,IAAI;IAQzD,aAAa,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI;IAIzC,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,iBAAiB,GAAG,IAAI;IA4CzE,qBAAqB,IAAI,OAAO;IAIhC,OAAO,CAAC,sBAAsB;IAyB9B,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,UAAU;IAiBlB,OAAO,CAAC,mBAAmB;IAuB3B;;;;OAIG;IACH,YAAY,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;IAI9C,8EAA8E;IAC9E,kBAAkB,IAAI,oBAAoB,EAAE;CAG7C;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CA2BxE;AAsBD,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,qBAAqB,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAwClG;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAOzF;AAED,wBAAgB,uBAAuB,IAAI,MAAM,CA0ChD;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,qBAAa,qBAAqB;IAChC,OAAO,CAAC,IAAI,CAAyC;IACrD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IAEtC,QAAQ,IAAI,OAAO;IAInB,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAOlC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,qBAAqB;IA2C7C,OAAO,CAAC,KAAK;CAId;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAwC7D;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+NjF"}
1
+ {"version":3,"file":"launch.d.ts","sourceRoot":"","sources":["../../src/terminal-ui/launch.ts"],"names":[],"mappings":"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"}
@@ -18,6 +18,8 @@ exports.formatTerminalSessionPickerHeader = formatTerminalSessionPickerHeader;
18
18
  exports.formatTerminalEditPreviewHeader = formatTerminalEditPreviewHeader;
19
19
  exports.formatTerminalEditPreviewCandidate = formatTerminalEditPreviewCandidate;
20
20
  exports.renderTerminalBanner = renderTerminalBanner;
21
+ exports.renderTerminalContextStatus = renderTerminalContextStatus;
22
+ exports.promptText = promptText;
21
23
  exports.formatTerminalPermissionPrompt = formatTerminalPermissionPrompt;
22
24
  exports.parseEditInput = parseEditInput;
23
25
  exports.renderTerminalShortcuts = renderTerminalShortcuts;
@@ -34,9 +36,11 @@ const redaction_1 = require("../services/redaction");
34
36
  const completion_1 = require("./completion");
35
37
  const editor_1 = require("./editor");
36
38
  const raw_editor_1 = require("./raw-editor");
39
+ const output_queue_1 = require("./output-queue");
37
40
  const ACCENT = chalk_1.default.hex('#80E6E8');
38
41
  const DIM = chalk_1.default.hex('#567089');
39
42
  const ERROR = chalk_1.default.hex('#FF7A7A');
43
+ const WARNING = chalk_1.default.hex('#F2C14E');
40
44
  const TOOL = chalk_1.default.hex('#7FA2B8');
41
45
  const BORDER = chalk_1.default.hex('#38556A');
42
46
  function stripTrailingNewlines(text) {
@@ -109,7 +113,10 @@ function resolveTerminalSessionPickerInput(input, request) {
109
113
  };
110
114
  }
111
115
  if (numeric) {
112
- return { type: 'error', message: `No session at index ${numeric[1]} or id prefix "${trimmed}".` };
116
+ return {
117
+ type: 'error',
118
+ message: `No session at index ${numeric[1]} or id prefix "${trimmed}".`,
119
+ };
113
120
  }
114
121
  return {
115
122
  type: 'error',
@@ -163,9 +170,9 @@ function hasErrorLayerPrefix(message) {
163
170
  const lower = message.toLowerCase();
164
171
  return TERMINAL_ERROR_LAYERS.some(layer => {
165
172
  const label = layer.toLowerCase();
166
- return lower.startsWith(`[${label}] `)
167
- || lower.startsWith(`error [${label}]:`)
168
- || lower.startsWith(`error: [${label}] `);
173
+ return (lower.startsWith(`[${label}] `) ||
174
+ lower.startsWith(`error [${label}]:`) ||
175
+ lower.startsWith(`error: [${label}] `));
169
176
  });
170
177
  }
171
178
  function inferTerminalErrorLayer(message) {
@@ -180,16 +187,16 @@ function inferTerminalErrorLayer(message) {
180
187
  return 'session';
181
188
  if (/\b(renderer|terminal|tty|prompt|resize|input editor|scrollback)\b/u.test(lower))
182
189
  return 'renderer';
183
- if (/\btool\b/u.test(lower)
184
- || /\b(exec_command|read_file|write_file|edit_file|grep|glob|list_files)\b/u.test(lower)
185
- || /command exited with code/u.test(lower)
186
- || /path is a directory|not a file|enoent|eacces/u.test(lower)) {
190
+ if (/\btool\b/u.test(lower) ||
191
+ /\b(exec_command|read_file|write_file|edit_file|grep|glob|list_files)\b/u.test(lower) ||
192
+ /command exited with code/u.test(lower) ||
193
+ /path is a directory|not a file|enoent|eacces/u.test(lower)) {
187
194
  return 'tool';
188
195
  }
189
- if (/\b(provider|model|llm|api|quota|rate limit|rate_limit|provider_busy)\b/u.test(lower)
190
- || /\b(openai|anthropic|dashscope|bailian|xunfei|glm|qwen)\b/u.test(lower)
191
- || /\bstatus code\b/u.test(lower)
192
- || /notEnoughCvError|engineInternalError/i.test(message)) {
196
+ if (/\b(provider|model|llm|api|quota|rate limit|rate_limit|provider_busy)\b/u.test(lower) ||
197
+ /\b(openai|anthropic|dashscope|bailian|xunfei|glm|qwen)\b/u.test(lower) ||
198
+ /\bstatus code\b/u.test(lower) ||
199
+ /notEnoughCvError|engineInternalError/i.test(message)) {
193
200
  return 'provider';
194
201
  }
195
202
  return 'runtime';
@@ -217,6 +224,16 @@ function formatTerminalSessionRestored(event) {
217
224
  if (view.summary) {
218
225
  lines.push(fitLine(' Summary: ', (0, redaction_1.redactTraceText)(view.summary)));
219
226
  }
227
+ if (view.summaryGeneratedAt) {
228
+ const origin = view.checkpointId ? 'compact checkpoint' : 'generated on resume';
229
+ lines.push(` Generated: ${new Date(view.summaryGeneratedAt).toLocaleString()} (${origin})`);
230
+ }
231
+ if (typeof view.summaryCoveredMessages === 'number') {
232
+ lines.push(` Covers: ${view.summaryCoveredMessages} source messages`);
233
+ }
234
+ if (typeof view.transcriptMessages === 'number') {
235
+ lines.push(`✔ Restored ${view.restoredMessages} model-context messages / ${view.transcriptMessages} transcript messages`);
236
+ }
220
237
  return lines.join('\n');
221
238
  }
222
239
  class DirectTerminalWriter {
@@ -343,6 +360,7 @@ class TerminalEventSink {
343
360
  this.entries = new Map();
344
361
  this.printedContent = new Map();
345
362
  this.pendingAssistantOutput = new Map();
363
+ this.finalizedEntryIds = new Set();
346
364
  this.idCounter = 0;
347
365
  this.pendingPicker = null;
348
366
  this.pickerOffset = 0;
@@ -358,14 +376,25 @@ class TerminalEventSink {
358
376
  }
359
377
  append(entry) {
360
378
  const id = `terminal-${++this.idCounter}`;
379
+ const { live, ...transcriptEntry } = entry;
361
380
  const fullEntry = {
362
381
  id,
363
- role: entry.role,
364
- title: entry.title,
365
- content: entry.content,
382
+ ...transcriptEntry,
366
383
  };
367
384
  this.entries.set(id, fullEntry);
368
- this.printEntry(fullEntry, false);
385
+ const finalized = live !== true;
386
+ const write = this.printEntry(fullEntry, finalized);
387
+ if (finalized) {
388
+ if (write instanceof Promise) {
389
+ void write.then(written => {
390
+ if (written)
391
+ this.releaseEntryBody(id);
392
+ });
393
+ }
394
+ else {
395
+ this.releaseEntryBody(id);
396
+ }
397
+ }
369
398
  return id;
370
399
  }
371
400
  update(id, patch) {
@@ -382,11 +411,22 @@ class TerminalEventSink {
382
411
  return;
383
412
  const next = patch ? { ...existing, ...patch } : existing;
384
413
  this.entries.set(id, next);
385
- this.printEntry(next, true);
414
+ const write = this.printEntry(next, true);
415
+ if (write instanceof Promise) {
416
+ void write.then(written => {
417
+ if (written)
418
+ this.releaseEntryBody(id);
419
+ });
420
+ }
421
+ else {
422
+ this.releaseEntryBody(id);
423
+ }
386
424
  }
387
425
  remove(id) {
388
426
  this.entries.delete(id);
389
427
  this.printedContent.delete(id);
428
+ this.pendingAssistantOutput.delete(id);
429
+ this.finalizedEntryIds.delete(id);
390
430
  }
391
431
  replaceTranscript(entries) {
392
432
  this.entries.clear();
@@ -472,7 +512,12 @@ class TerminalEventSink {
472
512
  case 'selected':
473
513
  this.pendingPicker = null;
474
514
  this.pickerOffset = 0;
475
- return { type: 'select_session', sessionId: selection.sessionId, allProjects: picker.allProjects, source: 'picker' };
515
+ return {
516
+ type: 'select_session',
517
+ sessionId: selection.sessionId,
518
+ allProjects: picker.allProjects,
519
+ source: 'picker',
520
+ };
476
521
  case 'error':
477
522
  this.writer.write(`${ERROR(selection.message)}\n`);
478
523
  return '';
@@ -525,16 +570,17 @@ class TerminalEventSink {
525
570
  if (!entry.content)
526
571
  return;
527
572
  if (entry.role === 'assistant') {
528
- this.printAssistantDelta(entry, finalized);
529
- return;
573
+ return this.printAssistantDelta(entry, finalized);
530
574
  }
531
575
  const previous = this.printedContent.get(entry.id);
532
576
  if (previous === entry.content && !finalized)
533
577
  return;
534
578
  this.printedContent.set(entry.id, entry.content);
579
+ // v0.2.23: bound printed content.
580
+ this.evictIfNeeded(this.printedContent, TerminalEventSink.MAX_PRINTED_CONTENT);
535
581
  const formatted = formatTranscriptEntry(entry);
536
582
  if (formatted) {
537
- this.writer.write(`${formatted}\n`);
583
+ return this.writeWithAcknowledgement(`${formatted}\n`);
538
584
  }
539
585
  }
540
586
  printAssistantDelta(entry, finalized) {
@@ -545,19 +591,26 @@ class TerminalEventSink {
545
591
  const delta = next.startsWith(previous) ? next.slice(previous.length) : `\n${next}`;
546
592
  const pending = `${this.pendingAssistantOutput.get(entry.id) ?? ''}${delta}`;
547
593
  this.printedContent.set(entry.id, next);
594
+ // v0.2.23: bound printed content.
595
+ this.evictIfNeeded(this.printedContent, TerminalEventSink.MAX_PRINTED_CONTENT);
548
596
  const shouldFlush = finalized || pending.includes('\n') || visibleLength(pending) >= 80;
549
597
  if (shouldFlush) {
550
598
  this.pendingAssistantOutput.delete(entry.id);
551
599
  if (pending) {
552
- this.writer.write(pending);
600
+ return this.writeWithAcknowledgement(pending);
553
601
  }
554
602
  else if (finalized && next && !next.endsWith('\n')) {
555
- this.writer.write('\n');
603
+ return this.writeWithAcknowledgement('\n');
556
604
  }
557
605
  return;
558
606
  }
559
607
  this.pendingAssistantOutput.set(entry.id, pending);
560
608
  }
609
+ writeWithAcknowledgement(text) {
610
+ if (this.writer.writeAsync)
611
+ return this.writer.writeAsync(text);
612
+ this.writer.write(text);
613
+ }
561
614
  /**
562
615
  * R8: consume the typed subagent event into the shared timeline view-model.
563
616
  * Does not print (the chat-controller transcript summary already drives
@@ -565,13 +618,61 @@ class TerminalEventSink {
565
618
  */
566
619
  subtaskEvent(event) {
567
620
  this.subtaskTimeline.set(event.taskId, (0, ui_view_model_1.subtaskEventToTimelineEntry)(event));
621
+ // v0.2.23: bound subtask timeline.
622
+ this.evictIfNeeded(this.subtaskTimeline, TerminalEventSink.MAX_SUBTASK_TIMELINE);
568
623
  }
569
624
  /** R8: read-only access to the typed subagent timeline (for parity tests). */
570
625
  getSubtaskTimeline() {
571
626
  return Array.from(this.subtaskTimeline.values());
572
627
  }
628
+ // --- v0.2.23: bounded state helpers ---
629
+ /**
630
+ * After finalize, the entry content is in native scrollback.
631
+ * Replace the full body with a lightweight marker so memory doesn't grow
632
+ * with scrollback length.
633
+ */
634
+ releaseEntryBody(id) {
635
+ const entry = this.entries.get(id);
636
+ if (!entry)
637
+ return;
638
+ // Keep role/id/title but replace heavy content with a marker.
639
+ this.entries.set(id, {
640
+ ...entry,
641
+ content: `[scrollback:${entry.role} posted ${entry.content.length} chars]`,
642
+ });
643
+ this.printedContent.delete(id);
644
+ this.pendingAssistantOutput.delete(id);
645
+ this.finalizedEntryIds.delete(id);
646
+ this.finalizedEntryIds.add(id);
647
+ while (this.finalizedEntryIds.size > TerminalEventSink.MAX_FINALIZED_METADATA) {
648
+ const oldest = this.finalizedEntryIds.values().next().value;
649
+ if (!oldest)
650
+ break;
651
+ this.finalizedEntryIds.delete(oldest);
652
+ this.entries.delete(oldest);
653
+ }
654
+ }
655
+ /**
656
+ * Evict oldest entries from a Map when it exceeds the configured limit.
657
+ * Uses Map's insertion-order iteration — oldest entries are evicted first.
658
+ * Mirrors evictOldest in session-storage.ts; kept private to avoid a shared
659
+ * dependency on session-storage internals.
660
+ */
661
+ evictIfNeeded(map, limit) {
662
+ while (map.size > limit) {
663
+ const firstKey = map.keys().next().value;
664
+ if (firstKey !== undefined)
665
+ map.delete(firstKey);
666
+ else
667
+ break;
668
+ }
669
+ }
573
670
  }
574
671
  exports.TerminalEventSink = TerminalEventSink;
672
+ // --- v0.2.23: bounded state configuration ---
673
+ TerminalEventSink.MAX_FINALIZED_METADATA = 512;
674
+ TerminalEventSink.MAX_PRINTED_CONTENT = 512;
675
+ TerminalEventSink.MAX_SUBTASK_TIMELINE = 100;
575
676
  function renderTerminalBanner(runtime) {
576
677
  const width = Math.max(2, terminalContentWidth(88));
577
678
  const line = '─'.repeat(Math.max(0, width - 2));
@@ -599,9 +700,17 @@ function renderTerminalBanner(runtime) {
599
700
  function printBanner(runtime) {
600
701
  process.stdout.write(renderTerminalBanner(runtime));
601
702
  }
703
+ function renderTerminalContextStatus(runtime) {
704
+ const usage = runtime.store.getSnapshot().contextUsage;
705
+ const status = (0, ui_view_model_1.contextUsageStatusText)(usage);
706
+ if (!status)
707
+ return '';
708
+ return usage && usage.percent >= usage.warningThresholdPercent ? WARNING(status) : DIM(status);
709
+ }
602
710
  function promptText(runtime) {
603
711
  const session = runtime.getSession()?.id.slice(0, 8) ?? 'new';
604
- return `${DIM(`[${session}]`)} ${ACCENT('›')} `;
712
+ const context = renderTerminalContextStatus(runtime);
713
+ return `${DIM(`[${session}]`)}${context ? ` ${context}` : ''} ${ACCENT('›')} `;
605
714
  }
606
715
  function compactPermissionValue(value, maxWidth) {
607
716
  const singleLine = (0, redaction_1.redactTraceText)(value).replace(/\s+/g, ' ').trim();
@@ -666,6 +775,7 @@ function renderTerminalShortcuts() {
666
775
  `${ACCENT('Shortcuts')}`,
667
776
  `${BORDER('─'.repeat(Math.min(width, 32)))}`,
668
777
  `${DIM('Enter')} send ${DIM('Tab')} complete`,
778
+ `${DIM('Ctrl+J')} newline`,
669
779
  `${DIM('Ctrl+C')} interrupt; twice exits`,
670
780
  `${DIM('/paste')} ${DIM('/edit')} ${DIM('/resume')}`,
671
781
  `${DIM('/last-tool')} ${DIM('/trace')}`,
@@ -677,6 +787,7 @@ function renderTerminalShortcuts() {
677
787
  `${ACCENT('Shortcuts')}`,
678
788
  `${BORDER('─'.repeat(Math.min(width, 40)))}`,
679
789
  `${DIM('Enter')} send ${DIM('Tab')} complete ${DIM('↑/↓')} history`,
790
+ `${DIM('Alt+Enter/Ctrl+J')} newline`,
680
791
  `${DIM('Ctrl+U/W')} edit ${DIM('Ctrl+C')} interrupt; twice exits`,
681
792
  `${DIM('/paste')} multiline ${DIM('/edit')} editor ${DIM('/resume')} sessions`,
682
793
  `${DIM('/last-tool')} tool detail ${DIM('/trace')} timeline`,
@@ -687,6 +798,7 @@ function renderTerminalShortcuts() {
687
798
  `${ACCENT('Terminal shortcuts')}`,
688
799
  `${BORDER('─'.repeat(48))}`,
689
800
  `${DIM('Enter')} send current input`,
801
+ `${DIM('Alt+Enter')} insert newline (${DIM('Ctrl+J')} also works)`,
690
802
  `${DIM('Tab')} complete slash command or @file mention`,
691
803
  `${DIM('↑/↓')} navigate local input history`,
692
804
  `${DIM('Ctrl+U')} clear current input`,
@@ -720,7 +832,9 @@ class TerminalInputComposer {
720
832
  if (!this.mode && ['/paste', '/multi', '/multiline'].includes(trimmed)) {
721
833
  this.mode = 'paste';
722
834
  this.lines.length = 0;
723
- return { notice: DIM('Multiline input: paste or type lines, finish with /end, cancel with /cancel.') };
835
+ return {
836
+ notice: DIM('Multiline input: paste or type lines, finish with /end, cancel with /cancel.'),
837
+ };
724
838
  }
725
839
  if (this.mode === 'paste') {
726
840
  if (trimmed === '/cancel') {
@@ -730,7 +844,9 @@ class TerminalInputComposer {
730
844
  if (trimmed === '/end') {
731
845
  const submitted = this.lines.join('\n').trimEnd();
732
846
  this.reset();
733
- return submitted ? { input: submitted } : { cancelled: true, notice: DIM('Multiline input was empty.') };
847
+ return submitted
848
+ ? { input: submitted }
849
+ : { cancelled: true, notice: DIM('Multiline input was empty.') };
734
850
  }
735
851
  this.lines.push(input);
736
852
  return {};
@@ -797,12 +913,36 @@ function normalizeTerminalAnswer(input) {
797
913
  }
798
914
  async function launchTerminalUI(runtime) {
799
915
  printBanner(runtime);
800
- let editor;
801
- const writer = {
802
- write: text => editor.writeExternal(text),
916
+ let agentController;
917
+ let writer;
918
+ const editor = new raw_editor_1.RawTerminalEditor({
919
+ cwd: runtime.cwd,
920
+ onSubmit: input => handleInput(input),
921
+ onCtrlC: () => handleSigint(),
922
+ onNotice: message => { void writer.write(`${DIM(message)}\n`); },
923
+ });
924
+ const outputAdapter = {
925
+ write: text => editor.writeExternalBatch([text]),
926
+ on: (event, listener) => { process.stdout.on(event, listener); },
927
+ off: (event, listener) => { process.stdout.off(event, listener); },
928
+ };
929
+ const outputQueue = new output_queue_1.TerminalOutputQueue(outputAdapter);
930
+ let outputBatchSequence = 0;
931
+ writer = {
932
+ write: text => {
933
+ void outputQueue.enqueue({
934
+ id: `terminal-output-${++outputBatchSequence}`,
935
+ chunks: [text],
936
+ releaseEntryIds: [],
937
+ }).catch(() => undefined);
938
+ },
939
+ writeAsync: text => outputQueue.enqueue({
940
+ id: `terminal-output-${++outputBatchSequence}`,
941
+ chunks: [text],
942
+ releaseEntryIds: [],
943
+ }).then(() => true, () => false),
803
944
  };
804
945
  const events = new TerminalEventSink(runtime, writer);
805
- let agentController;
806
946
  let stopping = false;
807
947
  let settled = false;
808
948
  let resolveLaunch = null;
@@ -823,21 +963,25 @@ async function launchTerminalUI(runtime) {
823
963
  return undefined;
824
964
  }
825
965
  confirmingTool = true;
826
- void editor.ask(formatTerminalPermissionPrompt(event.request, runtime.cwd), event.request.abortSignal).then(answer => {
966
+ void editor
967
+ .ask(formatTerminalPermissionPrompt(event.request, runtime.cwd), event.request.abortSignal)
968
+ .then(answer => {
827
969
  agentController.handle({
828
970
  type: 'permission_decision',
829
971
  requestId: event.request.id,
830
972
  approved: /^y(es)?$/i.test(answer.trim()),
831
973
  source: 'keyboard',
832
974
  });
833
- }).catch(() => {
975
+ })
976
+ .catch(() => {
834
977
  agentController.handle({
835
978
  type: 'permission_decision',
836
979
  requestId: event.request.id,
837
980
  approved: false,
838
981
  source: 'programmatic',
839
982
  });
840
- }).finally(() => {
983
+ })
984
+ .finally(() => {
841
985
  confirmingTool = false;
842
986
  prompt();
843
987
  });
@@ -861,12 +1005,6 @@ async function launchTerminalUI(runtime) {
861
1005
  events.append({ role: 'error', content: message });
862
1006
  },
863
1007
  });
864
- editor = new raw_editor_1.RawTerminalEditor({
865
- cwd: runtime.cwd,
866
- onSubmit: input => handleInput(input),
867
- onCtrlC: () => handleSigint(),
868
- onNotice: message => writer.write(`${DIM(message)}\n`),
869
- });
870
1008
  const prompt = () => {
871
1009
  if (stopping)
872
1010
  return;
@@ -883,8 +1021,16 @@ async function launchTerminalUI(runtime) {
883
1021
  return;
884
1022
  stopping = true;
885
1023
  await agentController.stopActiveTurn();
886
- editor.stop();
887
- await runtime.shutdown();
1024
+ try {
1025
+ await outputQueue.close();
1026
+ }
1027
+ catch {
1028
+ // Terminal output failure must not block shutdown.
1029
+ }
1030
+ finally {
1031
+ editor.stop();
1032
+ await runtime.shutdown();
1033
+ }
888
1034
  process.stdout.write('\n');
889
1035
  finishLaunch();
890
1036
  };
@@ -937,7 +1083,11 @@ async function launchTerminalUI(runtime) {
937
1083
  if (!stopping)
938
1084
  editor.start();
939
1085
  if (result.error) {
940
- events.append({ role: 'error', content: `Editor failed: ${result.error}`, errorLayer: 'renderer' });
1086
+ events.append({
1087
+ role: 'error',
1088
+ content: `Editor failed: ${result.error}`,
1089
+ errorLayer: 'renderer',
1090
+ });
941
1091
  prompt();
942
1092
  return;
943
1093
  }
@@ -981,7 +1131,7 @@ async function launchTerminalUI(runtime) {
981
1131
  prompt();
982
1132
  };
983
1133
  try {
984
- process.stdout.write(`${DIM('Ready. Stable terminal editor is enabled for CJK input, Backspace, multiline paste, and live revision. /paste and /edit are available for long input.')}\n`);
1134
+ process.stdout.write(`${DIM('Ready. Terminal editor supports CJK, Alt/Option+Enter or Ctrl+J newlines, multiline paste, and live revision. /edit is available for oversized drafts.')}\n`);
985
1135
  editor.start();
986
1136
  prompt();
987
1137
  await new Promise(resolve => {
@@ -991,8 +1141,16 @@ async function launchTerminalUI(runtime) {
991
1141
  finally {
992
1142
  if (!stopping) {
993
1143
  stopping = true;
994
- editor.stop();
995
- await runtime.shutdown();
1144
+ try {
1145
+ await outputQueue.close();
1146
+ }
1147
+ catch {
1148
+ // Terminal output failure must not block shutdown.
1149
+ }
1150
+ finally {
1151
+ editor.stop();
1152
+ await runtime.shutdown();
1153
+ }
996
1154
  process.stdout.write('\n');
997
1155
  }
998
1156
  }