@wrongstack/tui 0.297.0 → 0.298.1

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 (314) hide show
  1. package/dist/app-action-type.d.ts +25 -2
  2. package/dist/app-key-handler.d.ts +4 -0
  3. package/dist/app-props.d.ts +11 -1
  4. package/dist/app-settings-type.d.ts +19 -3
  5. package/dist/app-state.d.ts +6 -2
  6. package/dist/app-status-region.d.ts +7 -2
  7. package/dist/components/auth-panel.d.ts +4 -0
  8. package/dist/components/confirm-prompt.d.ts +14 -0
  9. package/dist/components/fleet-panel.d.ts +3 -1
  10. package/dist/components/history/copy-geometry.d.ts +61 -0
  11. package/dist/components/history/sage-output-format.d.ts +7 -6
  12. package/dist/components/history/scroll-controller-types.d.ts +116 -0
  13. package/dist/components/history/scrollbar-geometry.d.ts +60 -0
  14. package/dist/components/history/scrollbar-rail.d.ts +18 -0
  15. package/dist/components/history/selection-helpers.d.ts +111 -0
  16. package/dist/components/input.d.ts +8 -1
  17. package/dist/components/scrollable-history.d.ts +7 -136
  18. package/dist/components/settings-picker-model.d.ts +11 -1
  19. package/dist/components/settings-picker.d.ts +4 -4
  20. package/dist/components/sidebar-content.d.ts +47 -0
  21. package/dist/components/sidebar.d.ts +40 -0
  22. package/dist/components/status-bar-format.d.ts +10 -0
  23. package/dist/components/status-bar-types.d.ts +38 -5
  24. package/dist/components/status-bar.d.ts +1 -1
  25. package/dist/hit-test.d.ts +3 -2
  26. package/dist/hooks/use-provider-event-bridge.d.ts +1 -1
  27. package/dist/hooks/use-statusbar-view-model.d.ts +1 -0
  28. package/dist/hooks/use-tui-slash-commands.d.ts +1 -1
  29. package/dist/index.js +1803 -799
  30. package/dist/input-validation/action-types.d.ts +1 -1
  31. package/dist/markdown.d.ts +2 -0
  32. package/dist/reducers/helpers.d.ts +1 -1
  33. package/dist/reducers/workspace-panels.d.ts +1 -1
  34. package/dist/run-tui-options.d.ts +10 -1
  35. package/dist/settings-contracts.d.ts +1 -1
  36. package/dist/token-previews.d.ts +3 -2
  37. package/dist/ui-contracts.d.ts +9 -0
  38. package/package.json +11 -9
  39. package/dist/app-action-type.d.ts.map +0 -1
  40. package/dist/app-initial-state.d.ts.map +0 -1
  41. package/dist/app-key-handler.d.ts.map +0 -1
  42. package/dist/app-props.d.ts.map +0 -1
  43. package/dist/app-reducer.d.ts.map +0 -1
  44. package/dist/app-settings-type.d.ts.map +0 -1
  45. package/dist/app-state-core-types.d.ts.map +0 -1
  46. package/dist/app-state-fleet.d.ts.map +0 -1
  47. package/dist/app-state.d.ts.map +0 -1
  48. package/dist/app-status-region.d.ts.map +0 -1
  49. package/dist/app-ui-state.d.ts.map +0 -1
  50. package/dist/app-view-contract.d.ts.map +0 -1
  51. package/dist/app-view-state.d.ts.map +0 -1
  52. package/dist/app-view.d.ts.map +0 -1
  53. package/dist/app.d.ts.map +0 -1
  54. package/dist/auth-panel-model.d.ts.map +0 -1
  55. package/dist/brain-contracts.d.ts.map +0 -1
  56. package/dist/brain-panel-model.d.ts.map +0 -1
  57. package/dist/checkpoint-retention.d.ts.map +0 -1
  58. package/dist/clipboard.d.ts.map +0 -1
  59. package/dist/components/agents-monitor-constants.d.ts.map +0 -1
  60. package/dist/components/agents-monitor.d.ts.map +0 -1
  61. package/dist/components/animation-style.d.ts.map +0 -1
  62. package/dist/components/audit-panel.d.ts.map +0 -1
  63. package/dist/components/auth-panel-model.d.ts.map +0 -1
  64. package/dist/components/auth-panel.d.ts.map +0 -1
  65. package/dist/components/autonomy-picker.d.ts.map +0 -1
  66. package/dist/components/brain-decision-prompt.d.ts.map +0 -1
  67. package/dist/components/brain-panel-model.d.ts.map +0 -1
  68. package/dist/components/brain-panel.d.ts.map +0 -1
  69. package/dist/components/checkpoint-timeline.d.ts.map +0 -1
  70. package/dist/components/clear-confirm-panel.d.ts.map +0 -1
  71. package/dist/components/composer-status-chip.d.ts.map +0 -1
  72. package/dist/components/confirm-prompt.d.ts.map +0 -1
  73. package/dist/components/connections-panel.d.ts.map +0 -1
  74. package/dist/components/context-panel.d.ts.map +0 -1
  75. package/dist/components/continue-confirm-panel.d.ts.map +0 -1
  76. package/dist/components/coordinator-panel.d.ts.map +0 -1
  77. package/dist/components/cron-jobs.d.ts.map +0 -1
  78. package/dist/components/design-picker.d.ts.map +0 -1
  79. package/dist/components/enhance-panel.d.ts.map +0 -1
  80. package/dist/components/entry-error-boundary.d.ts.map +0 -1
  81. package/dist/components/esc-confirm-prompt.d.ts.map +0 -1
  82. package/dist/components/exit-confirm-panel.d.ts.map +0 -1
  83. package/dist/components/f-key-picker.d.ts.map +0 -1
  84. package/dist/components/file-picker.d.ts.map +0 -1
  85. package/dist/components/fleet-monitor.d.ts.map +0 -1
  86. package/dist/components/fleet-panel.d.ts.map +0 -1
  87. package/dist/components/goal-kanban-panel.d.ts.map +0 -1
  88. package/dist/components/goal-panel.d.ts.map +0 -1
  89. package/dist/components/help-overlay.d.ts.map +0 -1
  90. package/dist/components/help-panel.d.ts.map +0 -1
  91. package/dist/components/history/assistant.d.ts.map +0 -1
  92. package/dist/components/history/banner.d.ts.map +0 -1
  93. package/dist/components/history/basic-format.d.ts.map +0 -1
  94. package/dist/components/history/code-block-diff-helpers.d.ts.map +0 -1
  95. package/dist/components/history/code-block.d.ts.map +0 -1
  96. package/dist/components/history/copy-icon.d.ts.map +0 -1
  97. package/dist/components/history/entry.d.ts.map +0 -1
  98. package/dist/components/history/index.d.ts.map +0 -1
  99. package/dist/components/history/replay.d.ts.map +0 -1
  100. package/dist/components/history/sage-output-format.d.ts.map +0 -1
  101. package/dist/components/history/stream-box.d.ts.map +0 -1
  102. package/dist/components/history/tool-arg-format.d.ts.map +0 -1
  103. package/dist/components/history/tool-card.d.ts.map +0 -1
  104. package/dist/components/history/tool-group.d.ts.map +0 -1
  105. package/dist/components/history/tool-output-summary.d.ts.map +0 -1
  106. package/dist/components/history/tool-visual-command.d.ts.map +0 -1
  107. package/dist/components/history/tool-visual-domain.d.ts.map +0 -1
  108. package/dist/components/history/tool-visual-format.d.ts.map +0 -1
  109. package/dist/components/history/tool-visual-lsp.d.ts.map +0 -1
  110. package/dist/components/history/tool-visual-misc.d.ts.map +0 -1
  111. package/dist/components/history/tool-visual-mode-workdir.d.ts.map +0 -1
  112. package/dist/components/history/tool-visual-types.d.ts.map +0 -1
  113. package/dist/components/history/types.d.ts.map +0 -1
  114. package/dist/components/history/utils.d.ts.map +0 -1
  115. package/dist/components/history/visual-lines.d.ts.map +0 -1
  116. package/dist/components/history/visual-memory-logs.d.ts.map +0 -1
  117. package/dist/components/history.d.ts.map +0 -1
  118. package/dist/components/input.d.ts.map +0 -1
  119. package/dist/components/kanban-panel.d.ts.map +0 -1
  120. package/dist/components/key-hint-bar.d.ts.map +0 -1
  121. package/dist/components/live-activity-strip.d.ts.map +0 -1
  122. package/dist/components/mailbox-panel.d.ts.map +0 -1
  123. package/dist/components/mcp-picker.d.ts.map +0 -1
  124. package/dist/components/memory-context-widget.d.ts.map +0 -1
  125. package/dist/components/mode-picker.d.ts.map +0 -1
  126. package/dist/components/model-picker.d.ts.map +0 -1
  127. package/dist/components/monitor-shell.d.ts.map +0 -1
  128. package/dist/components/phase-monitor.d.ts.map +0 -1
  129. package/dist/components/phase-panel.d.ts.map +0 -1
  130. package/dist/components/plan-panel.d.ts.map +0 -1
  131. package/dist/components/plugin-picker.d.ts.map +0 -1
  132. package/dist/components/powerline-rail.d.ts.map +0 -1
  133. package/dist/components/process-list.d.ts.map +0 -1
  134. package/dist/components/project-picker.d.ts.map +0 -1
  135. package/dist/components/prompt-picker.d.ts.map +0 -1
  136. package/dist/components/provider-colors.d.ts.map +0 -1
  137. package/dist/components/queue-panel.d.ts.map +0 -1
  138. package/dist/components/refine-countdown-panel.d.ts.map +0 -1
  139. package/dist/components/refine-failure-panel.d.ts.map +0 -1
  140. package/dist/components/resume-picker.d.ts.map +0 -1
  141. package/dist/components/scrollable-history.d.ts.map +0 -1
  142. package/dist/components/sdd-board-overlay.d.ts.map +0 -1
  143. package/dist/components/send-mode-picker.d.ts.map +0 -1
  144. package/dist/components/sessions-panel.d.ts.map +0 -1
  145. package/dist/components/settings-picker-filter.d.ts.map +0 -1
  146. package/dist/components/settings-picker-jumps.d.ts.map +0 -1
  147. package/dist/components/settings-picker-model.d.ts.map +0 -1
  148. package/dist/components/settings-picker-row-list.d.ts.map +0 -1
  149. package/dist/components/settings-picker.d.ts.map +0 -1
  150. package/dist/components/shadow-panel.d.ts.map +0 -1
  151. package/dist/components/shell-command-warning.d.ts.map +0 -1
  152. package/dist/components/slash-confirm-panel.d.ts.map +0 -1
  153. package/dist/components/slash-menu.d.ts.map +0 -1
  154. package/dist/components/status-bar-chips.d.ts.map +0 -1
  155. package/dist/components/status-bar-format.d.ts.map +0 -1
  156. package/dist/components/status-bar-helpers.d.ts.map +0 -1
  157. package/dist/components/status-bar-types.d.ts.map +0 -1
  158. package/dist/components/status-bar.d.ts.map +0 -1
  159. package/dist/components/statusline-detail-panel.d.ts.map +0 -1
  160. package/dist/components/statusline-picker.d.ts.map +0 -1
  161. package/dist/components/suggestions.d.ts.map +0 -1
  162. package/dist/components/todos-monitor.d.ts.map +0 -1
  163. package/dist/components/tools-picker.d.ts.map +0 -1
  164. package/dist/components/worktree-monitor.d.ts.map +0 -1
  165. package/dist/components/worktree-panel.d.ts.map +0 -1
  166. package/dist/connections-health.d.ts.map +0 -1
  167. package/dist/connections-slash.d.ts.map +0 -1
  168. package/dist/context-fill.d.ts.map +0 -1
  169. package/dist/context-slash.d.ts.map +0 -1
  170. package/dist/cron-slash.d.ts.map +0 -1
  171. package/dist/esc-close-panels.d.ts.map +0 -1
  172. package/dist/exit-slash.d.ts.map +0 -1
  173. package/dist/f-key-panels.d.ts.map +0 -1
  174. package/dist/file-search.d.ts.map +0 -1
  175. package/dist/fn-keys.d.ts.map +0 -1
  176. package/dist/git-info.d.ts.map +0 -1
  177. package/dist/heap-watchdog.d.ts.map +0 -1
  178. package/dist/height-cache.d.ts.map +0 -1
  179. package/dist/highlight.d.ts.map +0 -1
  180. package/dist/history-archive.d.ts.map +0 -1
  181. package/dist/history-entry.d.ts.map +0 -1
  182. package/dist/history-retention.d.ts.map +0 -1
  183. package/dist/hit-test.d.ts.map +0 -1
  184. package/dist/hooks/fleet-chat-coalescer.d.ts.map +0 -1
  185. package/dist/hooks/subagent-history-format.d.ts.map +0 -1
  186. package/dist/hooks/use-app-picker-keys.d.ts.map +0 -1
  187. package/dist/hooks/use-app-runtime-refs.d.ts.map +0 -1
  188. package/dist/hooks/use-app-session-state.d.ts.map +0 -1
  189. package/dist/hooks/use-auth-panel.d.ts.map +0 -1
  190. package/dist/hooks/use-autonomous-coordinator.d.ts.map +0 -1
  191. package/dist/hooks/use-autonomy-drivers.d.ts.map +0 -1
  192. package/dist/hooks/use-brain-events.d.ts.map +0 -1
  193. package/dist/hooks/use-brain-panel.d.ts.map +0 -1
  194. package/dist/hooks/use-brain-risk-sync.d.ts.map +0 -1
  195. package/dist/hooks/use-chip-staleness-guard.d.ts.map +0 -1
  196. package/dist/hooks/use-client-telemetry.d.ts.map +0 -1
  197. package/dist/hooks/use-core-tui-commands.d.ts.map +0 -1
  198. package/dist/hooks/use-director-fleet-bridge.d.ts.map +0 -1
  199. package/dist/hooks/use-enhance-runtime-state.d.ts.map +0 -1
  200. package/dist/hooks/use-exit-command.d.ts.map +0 -1
  201. package/dist/hooks/use-file-search.d.ts.map +0 -1
  202. package/dist/hooks/use-fleet-generation-gate.d.ts.map +0 -1
  203. package/dist/hooks/use-git-session-status.d.ts.map +0 -1
  204. package/dist/hooks/use-help-panel.d.ts.map +0 -1
  205. package/dist/hooks/use-history-copy-notice.d.ts.map +0 -1
  206. package/dist/hooks/use-history-viewport-sync.d.ts.map +0 -1
  207. package/dist/hooks/use-initial-prompt.d.ts.map +0 -1
  208. package/dist/hooks/use-input-history-persistence.d.ts.map +0 -1
  209. package/dist/hooks/use-interrupt-ladder.d.ts.map +0 -1
  210. package/dist/hooks/use-kanban-board-focus.d.ts.map +0 -1
  211. package/dist/hooks/use-live-settings-state.d.ts.map +0 -1
  212. package/dist/hooks/use-live-todos.d.ts.map +0 -1
  213. package/dist/hooks/use-mailbox-view-model.d.ts.map +0 -1
  214. package/dist/hooks/use-mode-picker.d.ts.map +0 -1
  215. package/dist/hooks/use-model-pick.d.ts.map +0 -1
  216. package/dist/hooks/use-mouse-tracking.d.ts.map +0 -1
  217. package/dist/hooks/use-next-steps-auto-submit.d.ts.map +0 -1
  218. package/dist/hooks/use-panel-controllers.d.ts.map +0 -1
  219. package/dist/hooks/use-paste-handling.d.ts.map +0 -1
  220. package/dist/hooks/use-picker-keys-types.d.ts.map +0 -1
  221. package/dist/hooks/use-picker-keys.d.ts.map +0 -1
  222. package/dist/hooks/use-prompt-picker.d.ts.map +0 -1
  223. package/dist/hooks/use-provider-event-bridge.d.ts.map +0 -1
  224. package/dist/hooks/use-queue-manager.d.ts.map +0 -1
  225. package/dist/hooks/use-session-interrupt-controller.d.ts.map +0 -1
  226. package/dist/hooks/use-settings-auto-save.d.ts.map +0 -1
  227. package/dist/hooks/use-shadow-panel.d.ts.map +0 -1
  228. package/dist/hooks/use-slash-picker.d.ts.map +0 -1
  229. package/dist/hooks/use-stable-key-handler.d.ts.map +0 -1
  230. package/dist/hooks/use-statusbar-view-model.d.ts.map +0 -1
  231. package/dist/hooks/use-statusline-hidden-sync.d.ts.map +0 -1
  232. package/dist/hooks/use-statusline-state.d.ts.map +0 -1
  233. package/dist/hooks/use-stream-chip-expiration.d.ts.map +0 -1
  234. package/dist/hooks/use-subagent-events.d.ts.map +0 -1
  235. package/dist/hooks/use-terminal-render-lifecycle.d.ts.map +0 -1
  236. package/dist/hooks/use-todos-auto-clear.d.ts.map +0 -1
  237. package/dist/hooks/use-token-counter-refresh.d.ts.map +0 -1
  238. package/dist/hooks/use-tui-activity.d.ts.map +0 -1
  239. package/dist/hooks/use-tui-controllers.d.ts.map +0 -1
  240. package/dist/hooks/use-tui-environment-state.d.ts.map +0 -1
  241. package/dist/hooks/use-tui-event-bridge.d.ts.map +0 -1
  242. package/dist/hooks/use-tui-slash-commands.d.ts.map +0 -1
  243. package/dist/hooks/use-working-dir-chip.d.ts.map +0 -1
  244. package/dist/index.d.ts.map +0 -1
  245. package/dist/index.js.map +0 -7
  246. package/dist/ink.d.ts.map +0 -1
  247. package/dist/input-editing.d.ts.map +0 -1
  248. package/dist/input-key-router.d.ts.map +0 -1
  249. package/dist/input-tokens.d.ts.map +0 -1
  250. package/dist/input-validation/action-helpers.d.ts.map +0 -1
  251. package/dist/input-validation/action-types.d.ts.map +0 -1
  252. package/dist/input-validation/allow-lists.d.ts.map +0 -1
  253. package/dist/input-validation/limits.d.ts.map +0 -1
  254. package/dist/input-validation/result.d.ts.map +0 -1
  255. package/dist/input-validation/state-entries.d.ts.map +0 -1
  256. package/dist/input-validation/terminal.d.ts.map +0 -1
  257. package/dist/input-validation.d.ts.map +0 -1
  258. package/dist/kanban-audit.d.ts.map +0 -1
  259. package/dist/kanban-slash.d.ts.map +0 -1
  260. package/dist/kill-slash.d.ts.map +0 -1
  261. package/dist/layout-engine.d.ts.map +0 -1
  262. package/dist/layout-store.d.ts.map +0 -1
  263. package/dist/mailbox-view-model-types.d.ts.map +0 -1
  264. package/dist/markdown-table.d.ts.map +0 -1
  265. package/dist/markdown.d.ts.map +0 -1
  266. package/dist/memory-context-monitor.d.ts.map +0 -1
  267. package/dist/memory-lifecycle-entry.d.ts.map +0 -1
  268. package/dist/memory-slash-format.d.ts.map +0 -1
  269. package/dist/memory-slash.d.ts.map +0 -1
  270. package/dist/mouse.d.ts.map +0 -1
  271. package/dist/on-panel-open.d.ts.map +0 -1
  272. package/dist/overlay-key-router.d.ts.map +0 -1
  273. package/dist/paste-accumulator.d.ts.map +0 -1
  274. package/dist/prompt-refinement-start.d.ts.map +0 -1
  275. package/dist/ps-slash.d.ts.map +0 -1
  276. package/dist/queue-slash.d.ts.map +0 -1
  277. package/dist/reducers/activity.d.ts.map +0 -1
  278. package/dist/reducers/composer.d.ts.map +0 -1
  279. package/dist/reducers/conversation.d.ts.map +0 -1
  280. package/dist/reducers/dialogs.d.ts.map +0 -1
  281. package/dist/reducers/fleet.d.ts.map +0 -1
  282. package/dist/reducers/helpers.d.ts.map +0 -1
  283. package/dist/reducers/panel-pickers.d.ts.map +0 -1
  284. package/dist/reducers/settings-panel.d.ts.map +0 -1
  285. package/dist/reducers/settings-values.d.ts.map +0 -1
  286. package/dist/reducers/workspace-panels.d.ts.map +0 -1
  287. package/dist/rehydrate-history.d.ts.map +0 -1
  288. package/dist/run-blocks-controller.d.ts.map +0 -1
  289. package/dist/run-tui-client-registration.d.ts.map +0 -1
  290. package/dist/run-tui-options.d.ts.map +0 -1
  291. package/dist/run-tui-title-controller.d.ts.map +0 -1
  292. package/dist/run-tui.d.ts.map +0 -1
  293. package/dist/running-tools.d.ts.map +0 -1
  294. package/dist/scroll-anchor.d.ts.map +0 -1
  295. package/dist/sdd-lifecycle-entry.d.ts.map +0 -1
  296. package/dist/settings-contracts.d.ts.map +0 -1
  297. package/dist/shared-types.d.ts.map +0 -1
  298. package/dist/slash-command-search.d.ts.map +0 -1
  299. package/dist/steering-preamble.d.ts.map +0 -1
  300. package/dist/submit-controller.d.ts.map +0 -1
  301. package/dist/submit-history.d.ts.map +0 -1
  302. package/dist/submit-prompt-refinement.d.ts.map +0 -1
  303. package/dist/terminal-modes.d.ts.map +0 -1
  304. package/dist/terminal-silence.d.ts.map +0 -1
  305. package/dist/terminal-title.d.ts.map +0 -1
  306. package/dist/terminal-width.d.ts.map +0 -1
  307. package/dist/theme.d.ts.map +0 -1
  308. package/dist/thinking-word.d.ts.map +0 -1
  309. package/dist/token-previews.d.ts.map +0 -1
  310. package/dist/tool-glyph.d.ts.map +0 -1
  311. package/dist/tui-host-capabilities.d.ts.map +0 -1
  312. package/dist/tui-memory-counters.d.ts.map +0 -1
  313. package/dist/ui-contracts.d.ts.map +0 -1
  314. package/dist/ui-glyphs.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -1175,7 +1175,6 @@ function hasTokenDisplay(tokens) {
1175
1175
  return tokens.input > 0 || tokens.output > 0;
1176
1176
  }
1177
1177
  var RAIL_CAP = 1;
1178
- var RAIL_PAD = 2;
1179
1178
  function statusBarModelSpan(opts) {
1180
1179
  const leading = [];
1181
1180
  if (opts.yolo) leading.push(opts.monochrome ? "YOLO" : `${glyphs.warning} YOLO`);
@@ -1192,9 +1191,9 @@ function statusBarModelSpan(opts) {
1192
1191
  const workingDir = truncateChip(opts.workingDir, 28);
1193
1192
  leading.push(opts.monochrome ? workingDir : `${glyphs.workingDirectory} ${workingDir}`);
1194
1193
  }
1195
- const transitionWidth = 3;
1194
+ const sepWidth = 2;
1196
1195
  const precedingWidth = leading.reduce(
1197
- (total, text) => total + displayWidth(text) + RAIL_PAD + transitionWidth,
1196
+ (total, text) => total + displayWidth(text) + sepWidth,
1198
1197
  0
1199
1198
  );
1200
1199
  const full = opts.provider ? `${opts.provider}/${opts.model}` : opts.model;
@@ -1205,8 +1204,8 @@ function statusBarAutonomySpan(opts) {
1205
1204
  let col = RAIL_CAP;
1206
1205
  if (opts.yolo) {
1207
1206
  const yolo = opts.monochrome ? "YOLO" : `${glyphs.warning} YOLO`;
1208
- const transitionWidth = 3;
1209
- col += displayWidth(yolo) + RAIL_PAD + transitionWidth;
1207
+ const sepWidth = 2;
1208
+ col += displayWidth(yolo) + sepWidth;
1210
1209
  }
1211
1210
  const label = opts.monochrome ? opts.autonomy.toUpperCase() : `\u221E ${opts.autonomy.toUpperCase()}`;
1212
1211
  return { start: col + 1, len: displayWidth(label) };
@@ -1253,6 +1252,15 @@ function renderMeter(ratio, width) {
1253
1252
  }
1254
1253
  return "[" + bar + "]";
1255
1254
  }
1255
+ function blockMeter(ratio, width) {
1256
+ const clamped = Math.max(0, Math.min(1, ratio));
1257
+ const w = Math.max(1, width);
1258
+ const filledCount = Math.round(clamped * w);
1259
+ return {
1260
+ filled: "\u2588".repeat(filledCount),
1261
+ empty: "\u2591".repeat(Math.max(0, w - filledCount))
1262
+ };
1263
+ }
1256
1264
  function fmtTok(n) {
1257
1265
  if (n < 1e3) return String(n);
1258
1266
  if (n < 1e6) return `${(n / 1e3).toFixed(n < 1e4 ? 1 : 0)}k`;
@@ -1380,12 +1388,16 @@ var COMFORTABLE_THRESHOLD = 90;
1380
1388
  function chipColor(color, isNoColor) {
1381
1389
  return isNoColor ? void 0 : color;
1382
1390
  }
1391
+ var STACK_ORANGE = "#FD9F02";
1383
1392
  var LINE_BG_COLORS = [theme.surface, theme.surface, theme.surface, theme.surface];
1384
1393
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1385
1394
  var SPINNER_INTERVAL_MS = 1e3;
1386
1395
  function StatusBar({
1387
1396
  model,
1388
1397
  provider,
1398
+ version,
1399
+ latestVersion,
1400
+ updateAvailable,
1389
1401
  state,
1390
1402
  thinkingWord,
1391
1403
  thinkingAnimationStyle,
@@ -1414,11 +1426,15 @@ function StatusBar({
1414
1426
  memoryContextMonitor,
1415
1427
  contextStrategy,
1416
1428
  hiddenItems,
1429
+ // Component-level fallback stays 'detailed' for back-compat with callers/tests
1430
+ // that omit `mode`. The user-facing default is 'minimum' (DEFAULT_STATUSLINE_MODE),
1431
+ // applied at the app/settings layer — not here.
1417
1432
  mode = "detailed",
1418
1433
  events,
1419
1434
  sessionId,
1420
1435
  eternalStage,
1421
1436
  goalSummary,
1437
+ droppedTools,
1422
1438
  indexState,
1423
1439
  breakerCountdown,
1424
1440
  modeLabel,
@@ -1432,18 +1448,20 @@ function StatusBar({
1432
1448
  tokenSavingMode,
1433
1449
  toolCount,
1434
1450
  visibleChips = [],
1435
- sideEffectCount = 0
1451
+ sideEffectCount = 0,
1452
+ maxWidth
1436
1453
  }) {
1437
1454
  const { stdout } = useStdout();
1438
- const [termWidth, setTermWidth] = useState5(stdout?.columns ?? 90);
1455
+ const capWidth = (raw) => maxWidth ? Math.min(raw, maxWidth) : raw;
1456
+ const [termWidth, setTermWidth] = useState5(capWidth(stdout?.columns ?? 90));
1439
1457
  useEffect5(() => {
1440
- const handleResize = () => setTermWidth(stdout?.columns ?? 90);
1458
+ const handleResize = () => setTermWidth(capWidth(stdout?.columns ?? 90));
1441
1459
  handleResize();
1442
1460
  process.stdout.on("resize", handleResize);
1443
1461
  return () => {
1444
1462
  process.stdout.off("resize", handleResize);
1445
1463
  };
1446
- }, [stdout]);
1464
+ }, [stdout, maxWidth]);
1447
1465
  const isCompact = termWidth < COMPACT_THRESHOLD;
1448
1466
  const isComfortable = termWidth >= COMFORTABLE_THRESHOLD;
1449
1467
  const isNoColor = mode === "no-color";
@@ -1717,6 +1735,18 @@ function StatusBar({
1717
1735
  stateStatusChip,
1718
1736
  fleetWorkingTime != null && fleetWorkingTime > 0 && showChip("elapsed") ? /* @__PURE__ */ jsx5(Text, { dimColor: !isNoColor, children: isNoColor ? fmtElapsed(fleetWorkingTime) : `${STATUSLINE_ICONS.elapsed} ${fmtElapsed(fleetWorkingTime)}` }) : null
1719
1737
  ].filter((c) => c !== null);
1738
+ const showUpdateNotice = Boolean(updateAvailable) && typeof latestVersion === "string" && latestVersion.length > 0 && latestVersion !== version;
1739
+ const versionStatusChip = version ? /* @__PURE__ */ jsxs4(Text, { children: [
1740
+ /* @__PURE__ */ jsxs4(Text, { color: isNoColor ? void 0 : theme.textSecondary, dimColor: !isNoColor, children: [
1741
+ "v",
1742
+ version
1743
+ ] }),
1744
+ showUpdateNotice ? /* @__PURE__ */ jsxs4(Text, { color: isNoColor ? void 0 : STACK_ORANGE, children: [
1745
+ " \xB7 (update v",
1746
+ latestVersion,
1747
+ ")"
1748
+ ] }) : null
1749
+ ] }) : null;
1720
1750
  const minimumChips = [
1721
1751
  // State with animation
1722
1752
  showChip("state") && thinking ? /* @__PURE__ */ jsx5(
@@ -1774,10 +1804,6 @@ function StatusBar({
1774
1804
  ) : null,
1775
1805
  // Fleet working time
1776
1806
  fleetWorkingTime != null && fleetWorkingTime > 0 && showChip("elapsed") ? /* @__PURE__ */ jsx5(Text, { dimColor: !isNoColor, children: fmtElapsed(fleetWorkingTime) }) : null,
1777
- processMemory && showChip("memory") ? /* @__PURE__ */ jsxs4(Text, { color: chipColor(memoryColor, isNoColor), children: [
1778
- "RAM ",
1779
- fmtMemory(processMemory.rss)
1780
- ] }) : null,
1781
1807
  // Work summary (compact)
1782
1808
  ...minimalWorkParts.length > 0 ? [/* @__PURE__ */ jsx5(Text, { dimColor: !isNoColor, children: minimalWorkParts.slice(0, 2).join(" \xB7 ") })] : []
1783
1809
  ].filter((c) => c !== null);
@@ -1846,6 +1872,7 @@ function StatusBar({
1846
1872
  PowerlineRail,
1847
1873
  {
1848
1874
  segments: minimumChips,
1875
+ rightAnchor: versionStatusChip,
1849
1876
  budget: Math.max(12, termWidth),
1850
1877
  monochrome: isNoColor,
1851
1878
  fillBg: LINE_BG_COLORS[0]
@@ -1857,6 +1884,7 @@ function StatusBar({
1857
1884
  PowerlineRail,
1858
1885
  {
1859
1886
  segments: isCompact ? modeChips.slice(0, 5) : modeChips,
1887
+ rightAnchor: versionStatusChip,
1860
1888
  budget: Math.max(12, termWidth),
1861
1889
  monochrome: isNoColor,
1862
1890
  fillBg: LINE_BG_COLORS[0]
@@ -2007,6 +2035,7 @@ function StatusBar({
2007
2035
  children: isNoColor ? `auto in ${autoProceedCountdown}s` : `${STATUSLINE_ICONS.auto_proceed} auto in ${autoProceedCountdown}s`
2008
2036
  }
2009
2037
  ) : null,
2038
+ droppedTools && droppedTools > 0 ? /* @__PURE__ */ jsx5(Text, { color: isNoColor ? void 0 : theme.warn, children: isNoColor ? `-${droppedTools} tools` : `${STATUSLINE_ICONS.tools} -${droppedTools}` }) : null,
2010
2039
  ...detailChips
2011
2040
  ].filter((c) => c !== null),
2012
2041
  budget: Math.max(12, termWidth),
@@ -3589,7 +3618,7 @@ var SETTINGS_PICKER_JUMP_CHORDS = Object.freeze([
3589
3618
  { mod: "alt-shift", letter: "b", field: 33, label: "Stream debug logging" },
3590
3619
  { mod: "alt-shift", letter: "g", field: 35, label: "Config scope" },
3591
3620
  { mod: "alt", letter: "n", field: 36, label: "Animation" },
3592
- { mod: "alt", letter: "p", field: 40, label: "Show agent swarm panel" },
3621
+ { mod: "alt", letter: "p", field: 40, label: "Agent swarm panel" },
3593
3622
  { mod: "alt", letter: "r", field: 41, label: "Pre-refine countdown" },
3594
3623
  { mod: "alt-shift", letter: "s", field: 43, label: "Show SAGE Memory Inject" },
3595
3624
  { mod: "alt-shift", letter: "t", field: 44, label: "SAGE Memory Inject threshold" }
@@ -3639,6 +3668,7 @@ var CONTEXT_MODE_DESCS = {
3639
3668
  deep: "Larger context for complex tasks"
3640
3669
  };
3641
3670
  var STATUSLINE_MODES = ["minimum", "detailed", "no-color"];
3671
+ var DEFAULT_STATUSLINE_MODE = "minimum";
3642
3672
  var REASONING_MODES = ["auto", "on", "off"];
3643
3673
  var REASONING_EFFORTS = [
3644
3674
  "none",
@@ -3651,8 +3681,8 @@ var REASONING_EFFORTS = [
3651
3681
  ];
3652
3682
  var CACHE_TTLS = ["default", "5m", "1h"];
3653
3683
  var STATUSLINE_MODE_DESCS = {
3654
- minimum: "Single line with essential chips only",
3655
- detailed: "Full multi-line statusline (default)",
3684
+ minimum: "Single line with essential chips only (default)",
3685
+ detailed: "Full multi-line statusline",
3656
3686
  "no-color": "Multiline statusline without colors or icons"
3657
3687
  };
3658
3688
  var MAX_ITERATIONS_PRESETS = [100, 200, 500, 1e3, 0];
@@ -3817,7 +3847,7 @@ var SETTINGS_FIELD_LABELS = [
3817
3847
  // 38
3818
3848
  "Show model reasoning",
3819
3849
  // 39
3820
- "Show agent swarm panel",
3850
+ "Agent swarm panel",
3821
3851
  // 40
3822
3852
  "Pre-refine countdown",
3823
3853
  // 41
@@ -3850,7 +3880,7 @@ function resolveSettingsFieldValue(field, input) {
3850
3880
  [33, "debugStream"],
3851
3881
  [37, "breakerEnabled"],
3852
3882
  [39, "showModelReasoning"],
3853
- [40, "showAgentSwarmPanel"],
3883
+ // [40, 'showAgentSwarmPanel'] — now an enum, see ENUM_FIELDS below
3854
3884
  [42, "readSymbols"],
3855
3885
  [43, "showSageMemoryInject"]
3856
3886
  ]);
@@ -3903,7 +3933,8 @@ function resolveSettingsFieldValue(field, input) {
3903
3933
  [32, "auditLevel", AUDIT_LEVELS],
3904
3934
  [34, "statuslineMode", STATUSLINE_MODES],
3905
3935
  [35, "configScope", CONFIG_SCOPES],
3906
- [36, "animationStyle", ANIMATION_STYLE_CHOICES]
3936
+ [36, "animationStyle", ANIMATION_STYLE_CHOICES],
3937
+ [40, "showAgentSwarmPanel", ["bottom", "sidebar", "off"]]
3907
3938
  ];
3908
3939
  for (const [f, key, values] of ENUM_FIELDS) {
3909
3940
  if (field !== f) continue;
@@ -4022,7 +4053,7 @@ function getSettingsFieldValue(values, field) {
4022
4053
  [33, "debugStream"],
4023
4054
  [37, "breakerEnabled"],
4024
4055
  [39, "showModelReasoning"],
4025
- [40, "showAgentSwarmPanel"],
4056
+ // [40, 'showAgentSwarmPanel'] — now an enum, see ENUM_KEYS below
4026
4057
  [42, "readSymbols"],
4027
4058
  [43, "showSageMemoryInject"]
4028
4059
  ];
@@ -4044,7 +4075,8 @@ function getSettingsFieldValue(values, field) {
4044
4075
  [32, "auditLevel"],
4045
4076
  [34, "statuslineMode"],
4046
4077
  [35, "configScope"],
4047
- [36, "animationStyle"]
4078
+ [36, "animationStyle"],
4079
+ [40, "showAgentSwarmPanel"]
4048
4080
  ];
4049
4081
  for (const [f, key] of ENUM_KEYS) {
4050
4082
  if (field !== f) continue;
@@ -4168,7 +4200,7 @@ var SETTINGS_DEFAULTS = Object.freeze({
4168
4200
  enhanceEnabled: true,
4169
4201
  enhanceLanguage: "original",
4170
4202
  debugStream: false,
4171
- statuslineMode: "detailed",
4203
+ statuslineMode: DEFAULT_STATUSLINE_MODE,
4172
4204
  reasoningMode: "auto",
4173
4205
  reasoningEffort: "high",
4174
4206
  reasoningPreserve: false,
@@ -4179,7 +4211,7 @@ var SETTINGS_DEFAULTS = Object.freeze({
4179
4211
  breakerEnabled: false,
4180
4212
  breakerAutoKillResetMs: 6e4,
4181
4213
  showModelReasoning: true,
4182
- showAgentSwarmPanel: true,
4214
+ showAgentSwarmPanel: "bottom",
4183
4215
  readSymbols: false,
4184
4216
  showSageMemoryInject: false,
4185
4217
  sageMemoryInjectThreshold: 0.85
@@ -4594,9 +4626,9 @@ function SettingsPicker({
4594
4626
  detail: "Show LLM reasoning blocks in chat history"
4595
4627
  },
4596
4628
  {
4597
- label: "Show agent swarm panel",
4598
- value: boolVal(showAgentSwarmPanel),
4599
- detail: "Show persistent agent activity and mission queue"
4629
+ label: "Agent swarm panel",
4630
+ value: showAgentSwarmPanel,
4631
+ detail: "bottom = lower region, sidebar = right sidebar, off = hidden"
4600
4632
  },
4601
4633
  {
4602
4634
  label: "Pre-refine countdown",
@@ -5932,7 +5964,7 @@ var F_KEY_PANEL_ENTRIES = [
5932
5964
  key: 12,
5933
5965
  label: "Kanban board panel",
5934
5966
  action: "toggleKanbanPanel",
5935
- helpKeys: "F12 or Ctrl+J",
5967
+ helpKeys: "F12 or Ctrl+Y",
5936
5968
  helpDescription: "kanban board panel (also /kanban)"
5937
5969
  },
5938
5970
  {
@@ -6213,7 +6245,12 @@ function useAppPickerKeys({
6213
6245
  });
6214
6246
  return;
6215
6247
  }
6216
- dispatch({ type: "replaceHistory", entries: result.entries, nextId: result.nextId });
6248
+ dispatch({
6249
+ type: "replaceHistory",
6250
+ entries: result.entries,
6251
+ nextId: result.nextId,
6252
+ contextSnapshot: result.contextSnapshot
6253
+ });
6217
6254
  dispatch({ type: "resumePickerClose" });
6218
6255
  dispatch({
6219
6256
  type: "addEntry",
@@ -6239,7 +6276,12 @@ function useAppPickerKeys({
6239
6276
  dispatch({ type: "sessionsPanelBusy", on: false });
6240
6277
  return;
6241
6278
  }
6242
- dispatch({ type: "replaceHistory", entries: result.entries, nextId: result.nextId });
6279
+ dispatch({
6280
+ type: "replaceHistory",
6281
+ entries: result.entries,
6282
+ nextId: result.nextId,
6283
+ contextSnapshot: result.contextSnapshot
6284
+ });
6243
6285
  dispatch({ type: "toggleSessionsPanel" });
6244
6286
  dispatch({
6245
6287
  type: "addEntry",
@@ -8588,7 +8630,7 @@ async function handleMemoryWrite(store, sub, rest) {
8588
8630
  try {
8589
8631
  const existing = await Sage.getSage(id);
8590
8632
  if (!existing) return { message: `No memory with id \`${id}\`.` };
8591
- await Sage.deleteSage(id, reason);
8633
+ await Sage.deleteSage(id, reason, { force: true });
8592
8634
  return { message: `Deleted \`${id}\`.` };
8593
8635
  } catch (err) {
8594
8636
  return { message: `Could not delete: ${memErr(err)}` };
@@ -9290,6 +9332,7 @@ function closePanels(state) {
9290
9332
  contextPanelOpen: false,
9291
9333
  connectionsPanelOpen: false,
9292
9334
  sessionsPanelOpen: false,
9335
+ sidebarFocused: false,
9293
9336
  settingsPicker: { ...state.settingsPicker, open: false },
9294
9337
  statuslinePicker: { ...state.statuslinePicker, open: false },
9295
9338
  pluginPicker: { ...state.pluginPicker, open: false },
@@ -9836,8 +9879,8 @@ function handleCollabDone(event, dispatch, stateRef) {
9836
9879
  // src/hooks/use-file-search.ts
9837
9880
  import * as fs2 from "node:fs/promises";
9838
9881
  import * as path2 from "node:path";
9839
- import { useEffect as useEffect14 } from "react";
9840
9882
  import { toErrorMessage as toErrorMessage4 } from "@wrongstack/core/utils";
9883
+ import { useEffect as useEffect14 } from "react";
9841
9884
 
9842
9885
  // src/file-search.ts
9843
9886
  import * as fs from "node:fs/promises";
@@ -10048,7 +10091,7 @@ var TOKEN_PREVIEWS_MAX_ENTRIES = 64;
10048
10091
  var TOKEN_PREVIEW_MAX_CHARS = 8 * 1024;
10049
10092
  var TOKEN_PREVIEW_MAX_LINES = 6;
10050
10093
  var TOKEN_PREVIEWS_MAX_CHARS = 256 * 1024;
10051
- var TEXT_FILE_ATTACHMENT_MAX_BYTES = 1024 * 1024;
10094
+ var TEXT_FILE_ATTACHMENT_INLINE_MAX_BYTES = 1024 * 1024;
10052
10095
  var TRUNCATION_MARKER = "\u2026 [preview truncated]";
10053
10096
  var ATTACHMENT_WRAPPER_RE = /^<(?:pasted|file(?: path="[^"]*")?)>\n([\s\S]*)\n<\/(?:pasted|file)>$/;
10054
10097
  function createTokenPreview(value, maxChars = TOKEN_PREVIEW_MAX_CHARS, maxLines = TOKEN_PREVIEW_MAX_LINES) {
@@ -10226,17 +10269,13 @@ function useFileSearch(options) {
10226
10269
  const absPath = path2.isAbsolute(picked) ? picked : path2.join(projectRoot, picked);
10227
10270
  try {
10228
10271
  const stat3 = await fs2.stat(absPath);
10229
- if (stat3.size > TEXT_FILE_ATTACHMENT_MAX_BYTES) {
10230
- throw new Error(
10231
- `file exceeds ${(TEXT_FILE_ATTACHMENT_MAX_BYTES / (1024 * 1024)).toFixed(0)} MiB attachment limit (${stat3.size.toLocaleString()} bytes)`
10232
- );
10233
- }
10234
- const data = await fs2.readFile(absPath, "utf8");
10235
- const bytes = Buffer.byteLength(data, "utf8");
10236
- if (bytes > TEXT_FILE_ATTACHMENT_MAX_BYTES) {
10237
- throw new Error(
10238
- `file exceeds ${(TEXT_FILE_ATTACHMENT_MAX_BYTES / (1024 * 1024)).toFixed(0)} MiB attachment limit (${bytes.toLocaleString()} UTF-8 bytes)`
10239
- );
10272
+ let data;
10273
+ if (stat3.size > TEXT_FILE_ATTACHMENT_INLINE_MAX_BYTES) {
10274
+ data = fileReadContract(picked, stat3.size);
10275
+ } else {
10276
+ const inline = await fs2.readFile(absPath, "utf8");
10277
+ const bytes = Buffer.byteLength(inline, "utf8");
10278
+ data = bytes > TEXT_FILE_ATTACHMENT_INLINE_MAX_BYTES ? fileReadContract(picked, bytes) : inline;
10240
10279
  }
10241
10280
  const token = await builder.registerFile({
10242
10281
  kind: "file",
@@ -10262,6 +10301,14 @@ function useFileSearch(options) {
10262
10301
  };
10263
10302
  return { onPickerEnter: acceptPickerSelection };
10264
10303
  }
10304
+ function fileReadContract(filePath, bytes) {
10305
+ return [
10306
+ "[File reference contract]",
10307
+ `Referenced project file: ${JSON.stringify(filePath)} (${bytes.toLocaleString()} bytes; content not inlined).`,
10308
+ "Before answering or modifying anything related to this reference, use the available file-reading tools to read the complete file.",
10309
+ "If a read is paginated or chunked, continue from the same path until EOF. Do not treat a partial read or preview as the complete file."
10310
+ ].join("\n");
10311
+ }
10265
10312
 
10266
10313
  // src/hooks/use-help-panel.ts
10267
10314
  import { useCallback as useCallback8 } from "react";
@@ -10541,14 +10588,20 @@ function replaySessionMessages(messages, events, startId) {
10541
10588
  push(ts, { kind: "thinking", text: block.thinking });
10542
10589
  }
10543
10590
  }
10544
- appendText(
10545
- message.role,
10546
- message.content.filter((block) => block.type === "text").map((block) => block.text).join(""),
10547
- ts,
10548
- !message.content.some((block) => block.type === "tool_use")
10549
- );
10591
+ const final = !message.content.some((block) => block.type === "tool_use");
10592
+ const textParts = [];
10593
+ const flushText = () => {
10594
+ const text = textParts.join("").trim();
10595
+ if (text) appendText(message.role, text, ts, final);
10596
+ textParts.length = 0;
10597
+ };
10550
10598
  for (const block of message.content) {
10599
+ if (block.type === "text") {
10600
+ textParts.push(block.text);
10601
+ continue;
10602
+ }
10551
10603
  if (block.type === "tool_use") {
10604
+ flushText();
10552
10605
  const end2 = toolEnds.get(block.id);
10553
10606
  const entry = push(ts, {
10554
10607
  kind: "tool",
@@ -10564,6 +10617,7 @@ function replaySessionMessages(messages, events, startId) {
10564
10617
  continue;
10565
10618
  }
10566
10619
  if (block.type !== "tool_result") continue;
10620
+ flushText();
10567
10621
  const existing = toolEntries.get(block.tool_use_id);
10568
10622
  if (existing) {
10569
10623
  existing.output = toolOutputPreview(block.content);
@@ -10583,6 +10637,7 @@ function replaySessionMessages(messages, events, startId) {
10583
10637
  outputLines: end?.outputLines
10584
10638
  });
10585
10639
  }
10640
+ flushText();
10586
10641
  }
10587
10642
  const dummyPending = /* @__PURE__ */ new Map();
10588
10643
  const dummyCompleted = /* @__PURE__ */ new Map();
@@ -11096,7 +11151,7 @@ function createInitialState(options) {
11096
11151
  enhanceEnabled: true,
11097
11152
  enhanceLanguage: "original",
11098
11153
  debugStream: false,
11099
- statuslineMode: "detailed",
11154
+ statuslineMode: DEFAULT_STATUSLINE_MODE,
11100
11155
  reasoningMode: "auto",
11101
11156
  reasoningEffort: "high",
11102
11157
  reasoningPreserve: false,
@@ -11109,7 +11164,7 @@ function createInitialState(options) {
11109
11164
  breakerEnabled: false,
11110
11165
  breakerAutoKillResetMs: 6e4,
11111
11166
  showModelReasoning: true,
11112
- showAgentSwarmPanel: true,
11167
+ showAgentSwarmPanel: "bottom",
11113
11168
  showSageMemoryInject: false,
11114
11169
  sageMemoryInjectThreshold: 0.85,
11115
11170
  readSymbols: false
@@ -11201,6 +11256,8 @@ function createInitialState(options) {
11201
11256
  contextPanelOpen: false,
11202
11257
  connectionsPanelOpen: false,
11203
11258
  sessionsPanelOpen: false,
11259
+ sidebarFocused: false,
11260
+ sidebarScrollOffset: 0,
11204
11261
  sessionsPanel: { sessions: [], busy: false, selected: -1 },
11205
11262
  sessionResumeConfirm: null,
11206
11263
  collabSession: null,
@@ -12720,11 +12777,19 @@ function reduceComposer(state, action) {
12720
12777
  const maxBannerId = banners.length > 0 ? Math.max(...banners.map((b) => b.id)) : 0;
12721
12778
  const shifted = action.entries.map((e, i) => ({ ...e, id: maxBannerId + 1 + i }));
12722
12779
  const nextId = maxBannerId + 1 + shifted.length;
12780
+ const snap = action.contextSnapshot;
12781
+ const leaderWithSnap = snap && snap.tokens > 0 ? {
12782
+ ...state.leader,
12783
+ ctxTokens: snap.tokens,
12784
+ ctxMaxTokens: snap.maxContext > 0 ? snap.maxContext : state.leader.ctxMaxTokens
12785
+ } : state.leader;
12723
12786
  return {
12724
12787
  ...state,
12725
12788
  entries: retainTuiHistory([...banners, ...shifted]),
12726
12789
  nextId,
12727
- historyGen: state.historyGen + 1
12790
+ historyGen: state.historyGen + 1,
12791
+ leader: leaderWithSnap,
12792
+ contextChipVersion: state.contextChipVersion + 1
12728
12793
  };
12729
12794
  }
12730
12795
  default:
@@ -13773,7 +13838,7 @@ function reduceSettingsValues(state, action) {
13773
13838
  };
13774
13839
  if (f === 34) {
13775
13840
  const i = STATUSLINE_MODES.indexOf(sp.statuslineMode);
13776
- const base = i < 0 ? STATUSLINE_MODES.indexOf("detailed") : i;
13841
+ const base = i < 0 ? STATUSLINE_MODES.indexOf(DEFAULT_STATUSLINE_MODE) : i;
13777
13842
  const next = (base + action.delta + STATUSLINE_MODES.length) % STATUSLINE_MODES.length;
13778
13843
  return {
13779
13844
  ...state,
@@ -13833,11 +13898,17 @@ function reduceSettingsValues(state, action) {
13833
13898
  ...state,
13834
13899
  settingsPicker: { ...sp, showModelReasoning: !sp.showModelReasoning, hint: void 0 }
13835
13900
  };
13836
- if (f === 40)
13901
+ if (f === 40) {
13902
+ const SWARM_CYCLE = ["bottom", "sidebar", "off"];
13903
+ const current = sp.showAgentSwarmPanel;
13904
+ const j = SWARM_CYCLE.indexOf(current);
13905
+ const base = j < 0 ? 0 : j;
13906
+ const next = SWARM_CYCLE[(base + action.delta + SWARM_CYCLE.length) % SWARM_CYCLE.length] ?? "bottom";
13837
13907
  return {
13838
13908
  ...state,
13839
- settingsPicker: { ...sp, showAgentSwarmPanel: !sp.showAgentSwarmPanel, hint: void 0 }
13909
+ settingsPicker: { ...sp, showAgentSwarmPanel: next, hint: void 0 }
13840
13910
  };
13911
+ }
13841
13912
  if (f === 41) {
13842
13913
  const j = PRE_REFINE_SECONDS_PRESETS.indexOf(sp.preRefineSeconds);
13843
13914
  const base = j < 0 ? 0 : j;
@@ -13859,7 +13930,11 @@ function reduceSettingsValues(state, action) {
13859
13930
  if (f === 43)
13860
13931
  return {
13861
13932
  ...state,
13862
- settingsPicker: { ...sp, showSageMemoryInject: !sp.showSageMemoryInject, hint: void 0 }
13933
+ settingsPicker: {
13934
+ ...sp,
13935
+ showSageMemoryInject: !sp.showSageMemoryInject,
13936
+ hint: void 0
13937
+ }
13863
13938
  };
13864
13939
  if (f === 44) {
13865
13940
  const j = SAGE_THRESHOLD_PRESETS.indexOf(sp.sageMemoryInjectThreshold);
@@ -13948,7 +14023,43 @@ function reduceSettingsValues(state, action) {
13948
14023
  }
13949
14024
  }
13950
14025
 
14026
+ // src/ui-contracts.ts
14027
+ var SIDEBAR_MISSION_ROWS = 8;
14028
+
13951
14029
  // src/reducers/workspace-panels.ts
14030
+ function computeMaxSidebarScroll(state, viewportHeight = 20) {
14031
+ let contentHeight = 0;
14032
+ contentHeight += 4;
14033
+ contentHeight += 3;
14034
+ const fleetEntries = Object.values(state.fleet);
14035
+ const leader = fleetEntries.find(
14036
+ (e) => e.id === "leader" || e.name === "Leader Agent"
14037
+ );
14038
+ const runningSubagents = fleetEntries.filter((e) => e !== leader).filter((e) => e.status === "running");
14039
+ const agentCap = leader ? 11 : 12;
14040
+ const shownAgents = (leader ? 1 : 0) + Math.min(runningSubagents.length, agentCap);
14041
+ const hasAgents = shownAgents > 0;
14042
+ contentHeight += 2 + (hasAgents ? 0 : 1);
14043
+ if (hasAgents) {
14044
+ contentHeight += shownAgents * 2;
14045
+ if (runningSubagents.length > agentCap) contentHeight += 1;
14046
+ contentHeight += 1;
14047
+ }
14048
+ const swarmMode = state.settingsPicker.showAgentSwarmPanel;
14049
+ if (swarmMode === "sidebar") {
14050
+ contentHeight += 1 + SIDEBAR_MISSION_ROWS + 1 + 1;
14051
+ }
14052
+ const liveSessionCount = state.sessionsPanel.sessions.length;
14053
+ const resumeSessionCount = state.resumePicker.sessions.length;
14054
+ if (liveSessionCount > 0 || resumeSessionCount > 0) {
14055
+ contentHeight += 1;
14056
+ contentHeight += Math.min(3, liveSessionCount);
14057
+ contentHeight += Math.min(3, resumeSessionCount);
14058
+ if (liveSessionCount > 0 && resumeSessionCount > 0) contentHeight += 1;
14059
+ }
14060
+ if (state.sidebarFocused) contentHeight += 2;
14061
+ return Math.max(0, contentHeight - viewportHeight);
14062
+ }
13952
14063
  var workspacePanelActionTypes = [
13953
14064
  "toggleMonitor",
13954
14065
  "toggleAgentsMonitor",
@@ -13959,6 +14070,9 @@ var workspacePanelActionTypes = [
13959
14070
  "toggleCronMonitor",
13960
14071
  "togglePlanPanel",
13961
14072
  "closeAllPanels",
14073
+ "toggleSidebarFocus",
14074
+ "sidebarScroll",
14075
+ "sidebarScrollReset",
13962
14076
  "toggleKanbanPanel",
13963
14077
  "toggleGoalPanel",
13964
14078
  "toggleGoalKanbanPanel",
@@ -14025,7 +14139,24 @@ function reduceWorkspacePanels(state, action) {
14025
14139
  return opening ? { ...state, ...closePanels(state), planPanelOpen: true } : { ...state, planPanelOpen: false };
14026
14140
  }
14027
14141
  case "closeAllPanels":
14028
- return { ...state, ...closePanels(state) };
14142
+ return { ...state, ...closePanels(state), sidebarFocused: false };
14143
+ case "toggleSidebarFocus":
14144
+ return state.sidebarFocused ? { ...state, sidebarFocused: false, sidebarScrollOffset: 0 } : { ...state, sidebarFocused: true };
14145
+ case "sidebarScroll": {
14146
+ const maxScroll = computeMaxSidebarScroll(
14147
+ state,
14148
+ action.viewportHeight
14149
+ );
14150
+ return {
14151
+ ...state,
14152
+ sidebarScrollOffset: Math.min(
14153
+ maxScroll,
14154
+ Math.max(0, state.sidebarScrollOffset + action.delta)
14155
+ )
14156
+ };
14157
+ }
14158
+ case "sidebarScrollReset":
14159
+ return { ...state, sidebarScrollOffset: 0 };
14029
14160
  case "toggleKanbanPanel": {
14030
14161
  const opening = !state.kanbanPanelOpen;
14031
14162
  return opening ? { ...state, ...closePanels(state), kanbanPanelOpen: true } : { ...state, kanbanPanelOpen: false };
@@ -14931,47 +15062,79 @@ import { useEffect as useEffect20, useRef as useRef13, useState as useState7 } f
14931
15062
  import { spawn } from "node:child_process";
14932
15063
  import { buildChildEnv } from "@wrongstack/core/utils";
14933
15064
  async function readGitInfo(cwd) {
15065
+ let added = 0;
15066
+ let deleted = 0;
15067
+ let untracked = 0;
14934
15068
  const [branchRes, numstatRes, statusRes] = await Promise.all([
14935
15069
  runGit(cwd, ["branch", "--show-current"]),
14936
- runGit(cwd, ["diff", "HEAD", "--numstat"]),
14937
- runGit(cwd, ["status", "--porcelain"])
15070
+ foldGit(cwd, ["diff", "HEAD", "--numstat"], (line) => {
15071
+ if (!line) return;
15072
+ const [a, d] = line.split(" ");
15073
+ if (a && a !== "-") added += Number.parseInt(a, 10) || 0;
15074
+ if (d && d !== "-") deleted += Number.parseInt(d, 10) || 0;
15075
+ }),
15076
+ foldGit(cwd, ["status", "--porcelain"], (line) => {
15077
+ if (line.startsWith("?? ")) untracked++;
15078
+ })
14938
15079
  ]);
14939
15080
  if (!branchRes.ok || !numstatRes.ok || !statusRes.ok) return null;
14940
15081
  const branch = branchRes.stdout.trim();
14941
15082
  const branchLabel = branch || await detachedShortSha(cwd) || "detached";
14942
- let added = 0;
14943
- let deleted = 0;
14944
- for (const line of numstatRes.stdout.split("\n")) {
14945
- if (!line) continue;
14946
- const [a, d] = line.split(" ");
14947
- if (a && a !== "-") added += Number.parseInt(a, 10) || 0;
14948
- if (d && d !== "-") deleted += Number.parseInt(d, 10) || 0;
14949
- }
14950
- let untracked = 0;
14951
- for (const line of statusRes.stdout.split("\n")) {
14952
- if (line.startsWith("?? ")) untracked++;
14953
- }
14954
15083
  return { branch: branchLabel, added, deleted, untracked };
14955
15084
  }
14956
15085
  async function detachedShortSha(cwd) {
14957
15086
  const res = await runGit(cwd, ["rev-parse", "--short", "HEAD"]);
14958
15087
  return res.ok ? res.stdout.trim() : null;
14959
15088
  }
15089
+ var MAX_RETAINED_STDOUT = 64 * 1024;
15090
+ var MAX_LINE_CHARS = 64 * 1024;
15091
+ function spawnGit(cwd, args) {
15092
+ return spawn("git", args, {
15093
+ cwd,
15094
+ env: buildChildEnv(),
15095
+ // Inherit stderr (silent) — we don't care about git's noise.
15096
+ stdio: ["ignore", "pipe", "ignore"],
15097
+ // Don't let a slow git hang the TUI.
15098
+ timeout: 3e3,
15099
+ windowsHide: true
15100
+ });
15101
+ }
15102
+ function foldGit(cwd, args, onLine) {
15103
+ return new Promise((resolve) => {
15104
+ try {
15105
+ const child = spawnGit(cwd, args);
15106
+ let carry = "";
15107
+ child.stdout?.setEncoding("utf8");
15108
+ child.stdout?.on("data", (chunk) => {
15109
+ carry += chunk;
15110
+ let start = 0;
15111
+ let nl = carry.indexOf("\n", start);
15112
+ while (nl !== -1) {
15113
+ onLine(carry.slice(start, nl));
15114
+ start = nl + 1;
15115
+ nl = carry.indexOf("\n", start);
15116
+ }
15117
+ if (start > 0) carry = carry.slice(start);
15118
+ if (carry.length > MAX_LINE_CHARS) carry = carry.slice(0, MAX_LINE_CHARS);
15119
+ });
15120
+ child.on("error", () => resolve({ ok: false }));
15121
+ child.on("close", (code) => {
15122
+ if (carry) onLine(carry);
15123
+ resolve({ ok: code === 0 });
15124
+ });
15125
+ } catch {
15126
+ resolve({ ok: false });
15127
+ }
15128
+ });
15129
+ }
14960
15130
  function runGit(cwd, args) {
14961
15131
  return new Promise((resolve) => {
14962
15132
  let stdout = "";
14963
15133
  try {
14964
- const child = spawn("git", args, {
14965
- cwd,
14966
- env: buildChildEnv(),
14967
- // Inherit stderr (silent) — we don't care about git's noise.
14968
- stdio: ["ignore", "pipe", "ignore"],
14969
- // Don't let a slow git hang the TUI.
14970
- timeout: 3e3,
14971
- windowsHide: true
14972
- });
14973
- child.stdout.setEncoding("utf8");
14974
- child.stdout.on("data", (chunk) => {
15134
+ const child = spawnGit(cwd, args);
15135
+ child.stdout?.setEncoding("utf8");
15136
+ child.stdout?.on("data", (chunk) => {
15137
+ if (stdout.length >= MAX_RETAINED_STDOUT) return;
14975
15138
  stdout += chunk;
14976
15139
  });
14977
15140
  child.on("error", () => resolve({ ok: false, stdout: "" }));
@@ -15077,7 +15240,7 @@ function useHistoryCopyNotice(dispatch) {
15077
15240
  import { useEffect as useEffect22, useLayoutEffect, useRef as useRef15, useState as useState8 } from "react";
15078
15241
 
15079
15242
  // src/hit-test.ts
15080
- var SCROLLBAR_HIT_WIDTH = 2;
15243
+ var SCROLLBAR_HIT_WIDTH = 3;
15081
15244
  function historyViewportRows(termRows, bottomHeight) {
15082
15245
  return Math.max(1, Math.floor(termRows) - Math.max(0, Math.floor(bottomHeight)));
15083
15246
  }
@@ -15164,7 +15327,7 @@ function useLiveSettingsState({
15164
15327
  confirmExit
15165
15328
  }) {
15166
15329
  const liveSettings = getSettings?.();
15167
- const liveStatuslineMode = liveSettings?.statuslineMode ?? "detailed";
15330
+ const liveStatuslineMode = liveSettings?.statuslineMode ?? DEFAULT_STATUSLINE_MODE;
15168
15331
  const liveAnimationStyle = liveSettings?.animationStyle ?? "rainbow";
15169
15332
  const liveThinkingWord = liveSettings?.thinkingWord ?? "thinking";
15170
15333
  const chimeRef = useRef17(chime);
@@ -15726,6 +15889,14 @@ ${GROUNDED_NO_PROGRESS_STEER}` : suggestion;
15726
15889
  import { toErrorMessage as toErrorMessage5 } from "@wrongstack/core/utils";
15727
15890
  import React2, { useEffect as useEffect28 } from "react";
15728
15891
 
15892
+ // src/app-settings-type.ts
15893
+ function coerceAgentSwarmMode(v) {
15894
+ if (v === true || v === void 0) return "bottom";
15895
+ if (v === false) return "off";
15896
+ if (v === "bottom" || v === "sidebar" || v === "off") return v;
15897
+ return "bottom";
15898
+ }
15899
+
15729
15900
  // src/on-panel-open.ts
15730
15901
  function createPanelOpenDispatcher(deps) {
15731
15902
  const { dispatch, openProjectPicker, openStatuslinePicker, openAuthPanel } = deps;
@@ -15927,7 +16098,7 @@ function usePanelControllers({
15927
16098
  enhanceEnabled: s2.enhanceEnabled ?? true,
15928
16099
  enhanceLanguage: s2.enhanceLanguage ?? "original",
15929
16100
  debugStream: s2.debugStream ?? false,
15930
- statuslineMode: s2.statuslineMode ?? "detailed",
16101
+ statuslineMode: s2.statuslineMode ?? DEFAULT_STATUSLINE_MODE,
15931
16102
  reasoningMode: s2.reasoningMode ?? "auto",
15932
16103
  reasoningEffort: s2.reasoningEffort ?? "high",
15933
16104
  reasoningPreserve: s2.reasoningPreserve ?? false,
@@ -15938,7 +16109,7 @@ function usePanelControllers({
15938
16109
  breakerEnabled: s2.breakerEnabled ?? false,
15939
16110
  breakerAutoKillResetMs: s2.breakerAutoKillResetMs ?? 6e4,
15940
16111
  showModelReasoning: s2.showModelReasoning ?? true,
15941
- showAgentSwarmPanel: s2.showAgentSwarmPanel ?? true,
16112
+ showAgentSwarmPanel: coerceAgentSwarmMode(s2.showAgentSwarmPanel),
15942
16113
  showSageMemoryInject: s2.showSageMemoryInject ?? false,
15943
16114
  sageMemoryInjectThreshold: s2.sageMemoryInjectThreshold ?? 0.85,
15944
16115
  readSymbols: s2.readSymbols ?? false
@@ -16403,15 +16574,9 @@ function usePromptPicker({
16403
16574
 
16404
16575
  // src/hooks/use-provider-event-bridge.ts
16405
16576
  import { tuiStreamFlushMs } from "@wrongstack/core/utils";
16577
+ import { DEFAULT_MIN_IMPORTANCE, DEFAULT_MIN_SCORE, MIN_RELATION_STRENGTH } from "@wrongstack/sage";
16406
16578
  import { isFinalTurnStopReason as isFinalTurnStopReason2 } from "@wrongstack/tools/next-steps";
16407
- import {
16408
- DEFAULT_MIN_IMPORTANCE,
16409
- DEFAULT_MIN_SCORE,
16410
- MIN_RELATION_STRENGTH
16411
- } from "@wrongstack/sage";
16412
- import {
16413
- useEffect as useEffect29
16414
- } from "react";
16579
+ import { useEffect as useEffect29 } from "react";
16415
16580
 
16416
16581
  // src/memory-lifecycle-entry.ts
16417
16582
  function memoryLifecycleEntry(event, payload) {
@@ -16733,11 +16898,7 @@ function useProviderEventBridge({
16733
16898
  if (prev && prev.toolUseId === e.id) {
16734
16899
  pendingToolStream = {
16735
16900
  ...prev,
16736
- text: retainStreamTail(
16737
- prev.text,
16738
- e.event.text,
16739
- MAX_TOOL_STREAM_RETAINED_CHARS
16740
- ),
16901
+ text: retainStreamTail(prev.text, e.event.text, MAX_TOOL_STREAM_RETAINED_CHARS),
16741
16902
  startedAt: prev.startedAt
16742
16903
  };
16743
16904
  } else {
@@ -16895,19 +17056,33 @@ function useProviderEventBridge({
16895
17056
  }
16896
17057
  });
16897
17058
  });
17059
+ const offChimeraReport = events.onPattern("chimera.report_available", (_event, payload) => {
17060
+ const report = payload;
17061
+ if (report.sessionId && report.sessionId !== agent.ctx.session.id) return;
17062
+ dispatch({
17063
+ type: "addEntry",
17064
+ entry: {
17065
+ kind: "warn",
17066
+ text: report.message ?? "\u{1F982} Chimera report ready. No follow-up started; open the mailbox to inspect it."
17067
+ }
17068
+ });
17069
+ });
16898
17070
  const offMemoryStale = events.on("memory.staled", (e) => {
17071
+ if (!memoryEventMatchesSession(e, agent.ctx.session.id)) return;
16899
17072
  dispatch({
16900
17073
  type: "addEntry",
16901
17074
  entry: { kind: "warn", text: `SAGE stale: ${e.memoryId} \u2014 ${e.reason}` }
16902
17075
  });
16903
17076
  });
16904
17077
  const offMemoryContradicted = events.on("memory.contradicted", (e) => {
17078
+ if (!memoryEventMatchesSession(e, agent.ctx.session.id)) return;
16905
17079
  dispatch({
16906
17080
  type: "addEntry",
16907
17081
  entry: { kind: "warn", text: `SAGE contradicted: ${e.memoryId}` }
16908
17082
  });
16909
17083
  });
16910
17084
  const offMemoryHygiene = events.on("memory.hygiene_completed", (e) => {
17085
+ if (!memoryEventMatchesSession(e, agent.ctx.session.id)) return;
16911
17086
  dispatch({
16912
17087
  type: "addEntry",
16913
17088
  entry: {
@@ -16971,6 +17146,7 @@ function useProviderEventBridge({
16971
17146
  pendingSageStats.clear();
16972
17147
  });
16973
17148
  const offMemoryLifecycle = events.onPattern("memory.*", (event, payload) => {
17149
+ if (!memoryEventMatchesSession(payload, agent.ctx.session.id)) return;
16974
17150
  const lifecycle = memoryLifecycleEntry(event, payload);
16975
17151
  if (!lifecycle) return;
16976
17152
  dispatch({ type: "addEntry", entry: { kind: "memory-lifecycle", ...lifecycle } });
@@ -16996,6 +17172,7 @@ function useProviderEventBridge({
16996
17172
  offTrustPersisted();
16997
17173
  offDelegateStart();
16998
17174
  offDelegateDone();
17175
+ offChimeraReport();
16999
17176
  offMemoryStale();
17000
17177
  offMemoryContradicted();
17001
17178
  offMemoryHygiene();
@@ -17795,6 +17972,8 @@ function useStatusbarViewModel({
17795
17972
  clearInterval(id);
17796
17973
  };
17797
17974
  }, [taskPath]);
17975
+ const providerMaxTools = agent.ctx.provider.maxToolsCount ?? 0;
17976
+ const droppedTools = providerMaxTools > 0 ? Math.max(0, (agent.ctx.tools?.length ?? 0) - providerMaxTools) : 0;
17798
17977
  return {
17799
17978
  contextBreakdown,
17800
17979
  currentContextTokens,
@@ -17805,7 +17984,8 @@ function useStatusbarViewModel({
17805
17984
  hasVisibleFleetPanel,
17806
17985
  entriesWithLeader,
17807
17986
  planCounts,
17808
- taskCounts
17987
+ taskCounts,
17988
+ droppedTools
17809
17989
  };
17810
17990
  }
17811
17991
 
@@ -19111,9 +19291,7 @@ import {
19111
19291
  setDesignOverrides
19112
19292
  } from "@wrongstack/core/design";
19113
19293
  import { toErrorMessage as toErrorMessage8 } from "@wrongstack/core/utils";
19114
- import {
19115
- useEffect as useEffect44
19116
- } from "react";
19294
+ import { useEffect as useEffect44 } from "react";
19117
19295
 
19118
19296
  // src/components/autonomy-picker.tsx
19119
19297
  import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
@@ -19278,7 +19456,9 @@ function useTuiSlashCommands({
19278
19456
  motion: pairs["motion"]
19279
19457
  });
19280
19458
  if (Object.keys(patch).length === 0) {
19281
- return { message: 'Usage: /design tune radius=lg density=compact font="\u2026" motion=snappy' };
19459
+ return {
19460
+ message: 'Usage: /design tune radius=lg density=compact font="\u2026" motion=snappy'
19461
+ };
19282
19462
  }
19283
19463
  const merged = await recordOverrides(projectRoot, patch, (/* @__PURE__ */ new Date()).toISOString());
19284
19464
  if (!merged) return { message: "No active kit. Pin one first: /design <kit-id>." };
@@ -19322,7 +19502,13 @@ ${menu}` };
19322
19502
  });
19323
19503
  const fsp = await import("node:fs/promises");
19324
19504
  const nodePath = await import("node:path");
19325
- const abs = nodePath.join(projectRoot, result.path);
19505
+ const { resolveMaterializeTarget } = await import("@wrongstack/core/design");
19506
+ let abs;
19507
+ try {
19508
+ abs = await resolveMaterializeTarget(result.path, projectRoot);
19509
+ } catch (e) {
19510
+ return { message: e.message };
19511
+ }
19326
19512
  try {
19327
19513
  await fsp.mkdir(nodePath.dirname(abs), { recursive: true });
19328
19514
  await fsp.writeFile(abs, result.content);
@@ -20113,7 +20299,8 @@ var Input = memo(function Input2({
20113
20299
  footerHint = "Enter send \xB7 @ file \xB7 / commands",
20114
20300
  hidden,
20115
20301
  placeholderHeight,
20116
- onKey
20302
+ onKey,
20303
+ maxWidth
20117
20304
  }) {
20118
20305
  const suppressInkEscRef = useRef32(false);
20119
20306
  const suppressInkBackspaceRef = useRef32(false);
@@ -20244,16 +20431,22 @@ var Input = memo(function Input2({
20244
20431
  };
20245
20432
  }, [stdin, disabled, onKey]);
20246
20433
  const { stdout } = useStdout();
20247
- const [cols, setCols] = useState20(stdout?.columns ?? 80);
20434
+ const [cols, setCols] = useState20(() => {
20435
+ const raw = stdout?.columns ?? 80;
20436
+ return maxWidth ? Math.min(raw, maxWidth) : raw;
20437
+ });
20248
20438
  useEffect48(() => {
20249
20439
  if (!stdout) return;
20250
- const onResize = () => setCols(stdout.columns ?? 80);
20440
+ const onResize = () => {
20441
+ const raw = stdout.columns ?? 80;
20442
+ setCols(maxWidth ? Math.min(raw, maxWidth) : raw);
20443
+ };
20251
20444
  onResize();
20252
20445
  stdout.on("resize", onResize);
20253
20446
  return () => {
20254
20447
  stdout.off("resize", onResize);
20255
20448
  };
20256
- }, [stdout]);
20449
+ }, [stdout, maxWidth]);
20257
20450
  const promptColor = disabled ? theme.error : theme.brandAccent;
20258
20451
  const contentWidth = inputContentWidth(cols);
20259
20452
  const rows = layoutInputRows(prompt, value, cursor, contentWidth);
@@ -21562,23 +21755,25 @@ function FleetPanel({
21562
21755
  roster,
21563
21756
  todos,
21564
21757
  nowTick,
21565
- collabSession
21758
+ collabSession,
21759
+ maxWidth
21566
21760
  }) {
21567
21761
  const { stdout } = useStdout();
21762
+ const capColumns = (raw) => maxWidth ? Math.min(raw, maxWidth) : raw;
21568
21763
  const [terminal, setTerminal] = useState23({
21569
- columns: stdout?.columns ?? 90,
21764
+ columns: capColumns(stdout?.columns ?? 90),
21570
21765
  rows: stdout?.rows ?? 24
21571
21766
  });
21572
21767
  useEffect50(() => {
21573
21768
  const handleResize = () => {
21574
- setTerminal({ columns: stdout?.columns ?? 90, rows: stdout?.rows ?? 24 });
21769
+ setTerminal({ columns: capColumns(stdout?.columns ?? 90), rows: stdout?.rows ?? 24 });
21575
21770
  };
21576
21771
  handleResize();
21577
21772
  process.stdout.on("resize", handleResize);
21578
21773
  return () => {
21579
21774
  process.stdout.off("resize", handleResize);
21580
21775
  };
21581
- }, [stdout]);
21776
+ }, [stdout, maxWidth]);
21582
21777
  const list = Object.values(entries);
21583
21778
  const leader = list.find(isLeaderEntry2);
21584
21779
  const now = nowTick ?? Date.now();
@@ -22151,6 +22346,7 @@ function helpSections() {
22151
22346
  const nav = [];
22152
22347
  nav.push(
22153
22348
  { keys: "\u2191/\u2193", desc: "previous / next input (empty prompt)" },
22349
+ { keys: "Shift+Tab", desc: "focus sidebar for scroll (\u2191/\u2193), Esc to unfocus" },
22154
22350
  { keys: "?", desc: "open this help (empty prompt)" }
22155
22351
  );
22156
22352
  return [
@@ -22679,7 +22875,7 @@ function KanbanPanel({
22679
22875
  /* @__PURE__ */ jsx24(Text, { dimColor: true, children: "|" }),
22680
22876
  /* @__PURE__ */ jsx24(Text, { children: board.title })
22681
22877
  ] }) : null,
22682
- /* @__PURE__ */ jsx24(Text, { dimColor: true, children: "| n/p board | Tab task | \u2190\u2192 move | c/a/d create/add/dup | C/T copy/transfer | Ctrl+J toggle | Esc close" })
22878
+ /* @__PURE__ */ jsx24(Text, { dimColor: true, children: "| n/p board | Tab task | \u2190\u2192 move | c/a/d create/add/dup | C/T copy/transfer | Ctrl+Y toggle | Esc close" })
22683
22879
  ] }),
22684
22880
  prompt ? /* @__PURE__ */ jsx24(PromptLine, { prompt }) : null,
22685
22881
  notice && !prompt ? /* @__PURE__ */ jsx24(Text, { color: "green", wrap: "truncate", children: notice }) : null,
@@ -24781,14 +24977,13 @@ function renderRunningTools(running) {
24781
24977
 
24782
24978
  // src/app-status-region.tsx
24783
24979
  import { Fragment as Fragment13, jsx as jsx37, jsxs as jsxs36 } from "react/jsx-runtime";
24784
- function resolveAgentSwarmPanelVisibility(settingsOpen, pickerValue, persistedValue) {
24785
- return settingsOpen ? pickerValue : persistedValue ?? true;
24786
- }
24787
- function AppStatusRegion({ host, runtime }) {
24980
+ function AppStatusRegion({ host, runtime, mainColumnWidth }) {
24788
24981
  const {
24789
24982
  agent,
24790
24983
  agentTranscripts,
24791
24984
  appVersion,
24985
+ latestVersion,
24986
+ updateAvailable,
24792
24987
  director,
24793
24988
  events,
24794
24989
  fleetRoster,
@@ -24858,7 +25053,8 @@ function AppStatusRegion({ host, runtime }) {
24858
25053
  hasVisibleFleetPanel,
24859
25054
  entriesWithLeader,
24860
25055
  planCounts,
24861
- taskCounts
25056
+ taskCounts,
25057
+ droppedTools
24862
25058
  } = statusbar;
24863
25059
  const { mailboxStatus, mailboxPanelOpen, mailboxMessages, mailboxAgents } = mailbox;
24864
25060
  const { lowerFunctionPanelOpen } = viewState;
@@ -24870,6 +25066,8 @@ function AppStatusRegion({ host, runtime }) {
24870
25066
  provider: liveProvider,
24871
25067
  model: liveModel,
24872
25068
  version: appVersion,
25069
+ latestVersion,
25070
+ updateAvailable,
24873
25071
  state: state.status,
24874
25072
  thinkingWord: displayThinkingWord,
24875
25073
  thinkingAnimationStyle: (
@@ -24884,6 +25082,7 @@ function AppStatusRegion({ host, runtime }) {
24884
25082
  queueCount: state.queue.length,
24885
25083
  yolo: yoloLive,
24886
25084
  autonomy: autonomyLive,
25085
+ droppedTools,
24887
25086
  startedAt,
24888
25087
  fleetWorkingTime: fleetWorkingTimeMs,
24889
25088
  todos,
@@ -24922,7 +25121,8 @@ function AppStatusRegion({ host, runtime }) {
24922
25121
  mailbox: mailboxStatus,
24923
25122
  tokenSavingMode: liveSettings?.featureTokenSaving ?? tokenSavingMode,
24924
25123
  toolCount: liveToolCount,
24925
- sideEffectCount: agent.ctx.sideEffects?.length ?? 0
25124
+ sideEffectCount: agent.ctx.sideEffects?.length ?? 0,
25125
+ maxWidth: mainColumnWidth
24926
25126
  }
24927
25127
  ) }),
24928
25128
  /* @__PURE__ */ jsx37(
@@ -25065,11 +25265,7 @@ function AppStatusRegion({ host, runtime }) {
25065
25265
  resumeConfirm: state.sessionResumeConfirm ? { sessionName: state.sessionResumeConfirm.sessionName } : void 0,
25066
25266
  currentSessionId: agent.ctx.session?.id
25067
25267
  }
25068
- ) : resolveAgentSwarmPanelVisibility(
25069
- state.settingsPicker.open,
25070
- state.settingsPicker.showAgentSwarmPanel,
25071
- liveSettings?.showAgentSwarmPanel
25072
- ) && (director || hasVisibleFleetPanel || state.collabSession) ? /* @__PURE__ */ jsx37(
25268
+ ) : (director || hasVisibleFleetPanel || state.collabSession) && (liveSettings?.showAgentSwarmPanel ?? "bottom") !== "off" && (liveSettings?.showAgentSwarmPanel ?? "bottom") !== "sidebar" ? /* @__PURE__ */ jsx37(
25073
25269
  FleetPanel,
25074
25270
  {
25075
25271
  entries: entriesWithLeader,
@@ -25077,7 +25273,8 @@ function AppStatusRegion({ host, runtime }) {
25077
25273
  roster: fleetRoster,
25078
25274
  todos: liveTodos,
25079
25275
  nowTick,
25080
- collabSession: state.collabSession
25276
+ collabSession: state.collabSession,
25277
+ maxWidth: mainColumnWidth
25081
25278
  }
25082
25279
  ) : null,
25083
25280
  state.goalRun && !lowerFunctionPanelOpen ? /* @__PURE__ */ jsx37(
@@ -25269,6 +25466,17 @@ var OAUTH_LABEL = {
25269
25466
  claude: { title: "Claude Pro/Max", detail: "\u2192 anthropic-oauth" },
25270
25467
  copilot: { title: "GitHub Copilot", detail: "\u2192 github-copilot" }
25271
25468
  };
25469
+ function formatExpiry(expiresAt) {
25470
+ if (!expiresAt) return null;
25471
+ const expiry = Date.parse(expiresAt);
25472
+ if (!Number.isFinite(expiry)) return null;
25473
+ const now = Date.now();
25474
+ const msLeft = expiry - now;
25475
+ if (msLeft <= 0) return { text: "expired", color: UI_COLORS.error };
25476
+ if (msLeft < 60 * 6e4) return { text: `${Math.round(msLeft / 6e4)}m left`, color: UI_COLORS.error };
25477
+ if (msLeft < 24 * 60 * 6e4) return { text: `${Math.round(msLeft / (60 * 6e4))}h left`, color: UI_COLORS.warning };
25478
+ return { text: `${Math.round(msLeft / (24 * 60 * 6e4))}d left`, color: UI_COLORS.inactive };
25479
+ }
25272
25480
  function keySummary(keyRow) {
25273
25481
  const method = keyRow.authMethod === "oauth" ? " oauth" : "";
25274
25482
  const created = keyRow.createdAt ? ` ${keyRow.createdAt.slice(0, 10)}` : "";
@@ -25301,6 +25509,7 @@ function renderRow2(row, focused, i) {
25301
25509
  case "key": {
25302
25510
  const k = row.keyRow;
25303
25511
  const badge = badgeForKind(k.authMethod);
25512
+ const expiry = formatExpiry(k.expiresAt);
25304
25513
  return /* @__PURE__ */ jsxs38(Text, { color: rowColor, wrap: "truncate-end", children: [
25305
25514
  marker,
25306
25515
  " ",
@@ -25309,7 +25518,11 @@ function renderRow2(row, focused, i) {
25309
25518
  k.label.padEnd(20),
25310
25519
  " ",
25311
25520
  badge ? /* @__PURE__ */ jsx39(Text, { color: badge.color, children: badge.label.padEnd(8) }) : null,
25312
- /* @__PURE__ */ jsx39(Text, { dimColor: true, children: keySummary(k) })
25521
+ /* @__PURE__ */ jsx39(Text, { dimColor: true, children: keySummary(k) }),
25522
+ expiry ? /* @__PURE__ */ jsxs38(Text, { color: expiry.color, children: [
25523
+ " ",
25524
+ expiry.text
25525
+ ] }) : null
25313
25526
  ] }, `k-${k.label}`);
25314
25527
  }
25315
25528
  case "provider-action":
@@ -26008,7 +26221,7 @@ function ClearConfirmPanel({
26008
26221
  }
26009
26222
 
26010
26223
  // src/components/confirm-prompt.tsx
26011
- import { writeOut as writeOut2 } from "@wrongstack/core/utils";
26224
+ import { unifiedDiff, writeOut as writeOut2 } from "@wrongstack/core/utils";
26012
26225
  import React6 from "react";
26013
26226
 
26014
26227
  // src/highlight.ts
@@ -26557,17 +26770,17 @@ function toolStreamBoxHeight(name) {
26557
26770
  return TOOL_STREAM_MARGIN_ROWS + TOOL_STREAM_HEADER_ROWS + contentRows2;
26558
26771
  }
26559
26772
  function streamBoxRows(text, maxLines, contentWidth) {
26560
- const trunc2 = (line) => line.length > contentWidth ? `${line.slice(0, contentWidth - 1)}\u2026` : line;
26773
+ const trunc3 = (line) => line.length > contentWidth ? `${line.slice(0, contentWidth - 1)}\u2026` : line;
26561
26774
  const lines = text.split("\n");
26562
26775
  const totalLines = lines.length;
26563
26776
  const hidden = Math.max(0, totalLines - maxLines);
26564
26777
  const rows = [];
26565
26778
  if (hidden > 0) {
26566
26779
  rows.push({ text: ` \u2026 ${hidden} more line${hidden === 1 ? "" : "s"} above`, italic: true });
26567
- for (const line of lines.slice(totalLines - (maxLines - 1))) rows.push({ text: trunc2(line) });
26780
+ for (const line of lines.slice(totalLines - (maxLines - 1))) rows.push({ text: trunc3(line) });
26568
26781
  } else {
26569
26782
  for (let i = 0; i < maxLines - totalLines; i++) rows.push({ text: "" });
26570
- for (const line of lines) rows.push({ text: trunc2(line) });
26783
+ for (const line of lines) rows.push({ text: trunc3(line) });
26571
26784
  }
26572
26785
  return rows;
26573
26786
  }
@@ -27479,12 +27692,7 @@ function numberFromParsedField2(fields, key) {
27479
27692
  }
27480
27693
 
27481
27694
  // src/components/history/sage-output-format.ts
27482
- var SAGE_INJECTOR_HEADINGS = /* @__PURE__ */ new Set([
27483
- "--- SAGE: task-aware project knowledge (Memory Injector) ---",
27484
- "--- SAGE: related project knowledge (Memory Injector) ---"
27485
- ]);
27486
- var SAGE_MEMORY_LINE = /^- \[[^\]]+\](?:\[[^\]]+\])* <memory id="[^"]+">.*<\/memory>(?: .*)?$/;
27487
- var SAGE_MEMORY_LINE_TRUNCATED = /^- \[[^\]]+\](?:\[[^\]]+\])* <memory id="[^"]+">.*…$/;
27695
+ import { splitSageOutputBlock } from "@wrongstack/core/utils/sage-output-block";
27488
27696
  var SAGE_MEMORY_DETAIL = /^- (?<labels>\[[^\]]+\](?:\[[^\]]+\])*) <memory id="(?<id>[^"]+)">(?<text>.*?)<\/memory>(?: \((?<anchor>[^)]+)\))?(?: \[(?<meta>[^\]]+)\])?$/;
27489
27697
  function unescapeFenceBody(value) {
27490
27698
  return value.replace(/&#39;/g, "'").replace(/&quot;/g, '"').replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&amp;/g, "&");
@@ -27512,26 +27720,8 @@ function parseSageMemoryLine(line) {
27512
27720
  };
27513
27721
  }
27514
27722
  function extractSageBlock(output) {
27515
- const lines = output.split("\n");
27516
- for (let sageIdx = lines.length - 1; sageIdx >= 0; sageIdx--) {
27517
- if (!SAGE_INJECTOR_HEADINGS.has(lines[sageIdx] ?? "")) continue;
27518
- const candidate = lines.slice(sageIdx);
27519
- if (candidate.length < 2) continue;
27520
- const rawMemoryLines = candidate.slice(1);
27521
- const memoryLines = rawMemoryLines.filter((line) => line.trim().length > 0);
27522
- if (memoryLines.length === 0 || !memoryLines.every(
27523
- (line, index) => SAGE_MEMORY_LINE.test(line) || index === memoryLines.length - 1 && SAGE_MEMORY_LINE_TRUNCATED.test(line)
27524
- )) {
27525
- continue;
27526
- }
27527
- let end = candidate.length;
27528
- while (end > 1 && candidate[end - 1].trim().length === 0) end--;
27529
- return {
27530
- cleanOutput: lines.slice(0, sageIdx).join("\n").trimEnd(),
27531
- sageLines: candidate.slice(0, end)
27532
- };
27533
- }
27534
- return { cleanOutput: output, sageLines: [] };
27723
+ const { body, sageLines } = splitSageOutputBlock(output);
27724
+ return { cleanOutput: body, sageLines };
27535
27725
  }
27536
27726
  function resolveEntrySage(output, sageLines) {
27537
27727
  if (sageLines && sageLines.length > 0) {
@@ -29020,10 +29210,21 @@ function stringifyInput(input) {
29020
29210
  function truncate2(s2, max) {
29021
29211
  return s2.length <= max ? s2 : `${s2.slice(0, max - 1)}\u2026`;
29022
29212
  }
29023
- function hasDiff(input) {
29024
- return Boolean(
29025
- input && typeof input === "object" && "diff" in input
29026
- );
29213
+ function payloadDiff(input) {
29214
+ if (!input || typeof input !== "object") return "";
29215
+ const obj = input;
29216
+ const filePath = typeof obj["path"] === "string" ? obj["path"] : "file";
29217
+ if (typeof obj["diff"] === "string" && obj["diff"]) return obj["diff"];
29218
+ const newString = obj["new_string"];
29219
+ if (typeof newString === "string") {
29220
+ const oldString = typeof obj["old_string"] === "string" ? obj["old_string"] : "";
29221
+ return unifiedDiff(oldString, newString, { fromFile: filePath, toFile: filePath, context: 2 });
29222
+ }
29223
+ const content = obj["content"];
29224
+ if (typeof content === "string" && content) {
29225
+ return unifiedDiff("", content, { fromFile: "/dev/null", toFile: filePath, context: 0 });
29226
+ }
29227
+ return "";
29027
29228
  }
29028
29229
  var CONFIRM_DIFF_MAX_LINES = 20;
29029
29230
  function renderDiffLine(line) {
@@ -29083,9 +29284,8 @@ function ConfirmPrompt({
29083
29284
  }
29084
29285
  });
29085
29286
  const inputSummary = stringifyInput(input);
29086
- const showDiff = hasDiff(input);
29087
29287
  const inp = input;
29088
- const diff = typeof inp?.diff === "string" ? inp.diff : "";
29288
+ const diff = payloadDiff(input);
29089
29289
  const diffPath = typeof inp?.path === "string" ? inp.path : void 0;
29090
29290
  return /* @__PURE__ */ jsxs46(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
29091
29291
  /* @__PURE__ */ jsxs46(Box, { flexDirection: "row", children: [
@@ -29098,7 +29298,7 @@ function ConfirmPrompt({
29098
29298
  "KANBAN BOUNDARY: ",
29099
29299
  boundaryReason
29100
29300
  ] }) : null,
29101
- showDiff && diff ? /* @__PURE__ */ jsx47(Box, { flexDirection: "column", marginY: 1, children: renderDiff(diff, diffPath) }) : null,
29301
+ diff ? /* @__PURE__ */ jsx47(Box, { flexDirection: "column", marginY: 1, children: renderDiff(diff, diffPath) }) : null,
29102
29302
  /* @__PURE__ */ jsx47(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
29103
29303
  /* @__PURE__ */ jsx47(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx47(Text, { children: buttonLabels(suggestedPattern).map((l) => /* @__PURE__ */ jsxs46(React6.Fragment, { children: [
29104
29304
  /* @__PURE__ */ jsx47(Text, { bold: true, color: BUTTON_COLOR[l.decision], children: l.bracket }),
@@ -31057,7 +31257,7 @@ function ResumePicker({
31057
31257
  const date = (s2.lastActivityAt ?? s2.startedAt).slice(0, 16).replace("T", " ");
31058
31258
  const displayName3 = s2.name?.trim() || s2.title || s2.id;
31059
31259
  const contentPreview = s2.lastUserMessage?.trim();
31060
- const outcomeBadge = s2.outcome === "completed" ? "\u2713 " : s2.outcome === "aborted" ? "\u26A0 " : s2.outcome === "error" ? "\u2717 " : s2.outcome === "timeout" ? "\u23F1 " : " ";
31260
+ const outcomeBadge2 = s2.outcome === "completed" ? "\u2713 " : s2.outcome === "aborted" ? "\u26A0 " : s2.outcome === "error" ? "\u2717 " : s2.outcome === "timeout" ? "\u23F1 " : " ";
31061
31261
  const toolStr = s2.toolCallCount > 0 ? `${s2.toolCallCount} tool${s2.toolCallCount === 1 ? "" : "s"}` : "";
31062
31262
  const iterStr = s2.iterationCount > 0 ? `${s2.iterationCount} iter${s2.iterationCount === 1 ? "" : "s"}` : "";
31063
31263
  return /* @__PURE__ */ jsxs62(Box, { flexDirection: "column", children: [
@@ -31082,7 +31282,7 @@ function ResumePicker({
31082
31282
  ),
31083
31283
  /* @__PURE__ */ jsxs62(Text, { dimColor: true, children: [
31084
31284
  isSelected ? " " : " ",
31085
- outcomeBadge,
31285
+ outcomeBadge2,
31086
31286
  s2.tokenTotal.toLocaleString(),
31087
31287
  " tok",
31088
31288
  (s2.messageCount ?? 0) > 0 ? ` \xB7 ${s2.messageCount} msg` : "",
@@ -32221,6 +32421,39 @@ function parseInline(text) {
32221
32421
  continue;
32222
32422
  }
32223
32423
  }
32424
+ if (ch === "[") {
32425
+ const textEnd = text.indexOf("]", i + 1);
32426
+ if (textEnd > i && text[textEnd + 1] === "(") {
32427
+ const urlEnd = text.indexOf(")", textEnd + 2);
32428
+ if (urlEnd > textEnd) {
32429
+ flush();
32430
+ const linkText = text.slice(i + 1, textEnd);
32431
+ tokens.push({ text: linkText, link: true });
32432
+ i = urlEnd + 1;
32433
+ continue;
32434
+ }
32435
+ }
32436
+ }
32437
+ if (text.startsWith("http://", i) || text.startsWith("https://", i)) {
32438
+ let urlEnd = i + 8;
32439
+ while (urlEnd < text.length) {
32440
+ const c = text[urlEnd];
32441
+ if (c !== void 0 && c.match(/[a-zA-Z0-9._~:/?#@!$&+,;=%\-\[\]()'*]/)) {
32442
+ urlEnd++;
32443
+ } else {
32444
+ break;
32445
+ }
32446
+ }
32447
+ const trailing = text.slice(i, urlEnd);
32448
+ const stripped = trailing.replace(/[.,;!?)]+$/, "");
32449
+ urlEnd = i + stripped.length;
32450
+ if (urlEnd > i + 8) {
32451
+ flush();
32452
+ tokens.push({ text: stripped, link: true });
32453
+ i = urlEnd;
32454
+ continue;
32455
+ }
32456
+ }
32224
32457
  plain += ch;
32225
32458
  i += 1;
32226
32459
  }
@@ -32238,7 +32471,7 @@ function InlineLine({ tokens, dim }) {
32238
32471
  return /* @__PURE__ */ jsx66(Text, { children: tokens.map((t, j) => /* @__PURE__ */ jsx66(
32239
32472
  Text,
32240
32473
  {
32241
- color: t.code ? theme.accent : "white",
32474
+ color: t.code ? theme.accent : t.link ? theme.accent : "white",
32242
32475
  bold: Boolean(t.bold),
32243
32476
  italic: Boolean(t.italic),
32244
32477
  strikethrough: Boolean(t.strike),
@@ -32395,7 +32628,7 @@ var ASSISTANT_TAIL_HEIGHT = ASSISTANT_TAIL_MARGIN_Y + ASSISTANT_TAIL_HEADER_ROWS
32395
32628
 
32396
32629
  // src/components/history/banner.tsx
32397
32630
  import { Fragment as Fragment22, jsx as jsx68, jsxs as jsxs66 } from "react/jsx-runtime";
32398
- var STACK_ORANGE = "#FD9F02";
32631
+ var STACK_ORANGE2 = "#FD9F02";
32399
32632
  var SIGNAL_PINK = "#FE2E5F";
32400
32633
  var BORDER = "#3B3C36";
32401
32634
  var MUTED = "#B6B2A8";
@@ -32429,7 +32662,7 @@ function BrandMark({ pinkRow = 1 }) {
32429
32662
  if (column === PINK_HOME && (row === pinkRow || row === pinkRow + 1)) {
32430
32663
  return SIGNAL_PINK;
32431
32664
  }
32432
- if (row < 2 && column !== PINK_HOME) return STACK_ORANGE;
32665
+ if (row < 2 && column !== PINK_HOME) return STACK_ORANGE2;
32433
32666
  return null;
32434
32667
  })
32435
32668
  );
@@ -32480,7 +32713,7 @@ var WORDMARK_LINES = Object.freeze(
32480
32713
  );
32481
32714
  function bannerGradientColor(position, length) {
32482
32715
  const progress = length > 1 ? position / (length - 1) : 0.5;
32483
- return mixHex(STACK_ORANGE, SIGNAL_PINK, progress);
32716
+ return mixHex(STACK_ORANGE2, SIGNAL_PINK, progress);
32484
32717
  }
32485
32718
  function GradientText({ text }) {
32486
32719
  return /* @__PURE__ */ jsx68(Text, { bold: true, children: [...text].map(
@@ -32505,7 +32738,7 @@ function InfoRow({
32505
32738
  }) {
32506
32739
  const labelWidth = compact ? 6 : 9;
32507
32740
  const valueWidth = Math.max(1, contentWidth - labelWidth - 3);
32508
- const color = accent ? STACK_ORANGE : MUTED;
32741
+ const color = accent ? STACK_ORANGE2 : MUTED;
32509
32742
  return /* @__PURE__ */ jsxs66(Text, { children: [
32510
32743
  /* @__PURE__ */ jsx68(Text, { color, children: icon }),
32511
32744
  /* @__PURE__ */ jsx68(Text, { color, bold: true, children: ` ${trunc(label, labelWidth).padEnd(labelWidth)} ` }),
@@ -32542,11 +32775,11 @@ function ProfileRow({
32542
32775
  const profileSegment = segmentMatch?.[1] ?? "";
32543
32776
  const segIdx = profileSegment ? displayPath.lastIndexOf(profileSegment) : -1;
32544
32777
  return /* @__PURE__ */ jsxs66(Text, { children: [
32545
- /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE, children: icon }),
32546
- /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE, bold: true, children: ` ${trunc(label, labelWidth).padEnd(labelWidth)} ` }),
32778
+ /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE2, children: icon }),
32779
+ /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE2, bold: true, children: ` ${trunc(label, labelWidth).padEnd(labelWidth)} ` }),
32547
32780
  segIdx >= 0 && profileSegment ? /* @__PURE__ */ jsxs66(Fragment22, { children: [
32548
32781
  /* @__PURE__ */ jsx68(Text, { color: MUTED, children: displayPath.slice(0, segIdx) }),
32549
- /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE, bold: true, children: profileSegment }),
32782
+ /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE2, bold: true, children: profileSegment }),
32550
32783
  /* @__PURE__ */ jsx68(Text, { color: MUTED, children: displayPath.slice(segIdx + profileSegment.length) })
32551
32784
  ] }) : /* @__PURE__ */ jsx68(Text, { color: MUTED, children: displayPath })
32552
32785
  ] });
@@ -32559,7 +32792,7 @@ function Footer({ contentWidth, compact }) {
32559
32792
  /* @__PURE__ */ jsx68(Text, { dimColor: true, children: OSC8_WRONGSTACK }),
32560
32793
  !compact || contentWidth >= 35 ? /* @__PURE__ */ jsxs66(Fragment22, { children: [
32561
32794
  /* @__PURE__ */ jsx68(Text, { dimColor: true, children: " \xB7 " }),
32562
- /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE, children: "\u2605 " }),
32795
+ /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE2, children: "\u2605 " }),
32563
32796
  /* @__PURE__ */ jsx68(Text, { dimColor: true, children: OSC8_GITHUB })
32564
32797
  ] }) : null
32565
32798
  ] }) });
@@ -32585,7 +32818,7 @@ function AutonomyAgentsSection({
32585
32818
  if (!agent) return null;
32586
32819
  const online = agent.online;
32587
32820
  const indicator = online ? "\u25CF" : "\xB7";
32588
- const color = online ? STACK_ORANGE : MUTED;
32821
+ const color = online ? STACK_ORANGE2 : MUTED;
32589
32822
  const detail = agent.detail;
32590
32823
  return /* @__PURE__ */ jsxs66(Box, { flexDirection: "row", marginRight: 2, children: [
32591
32824
  /* @__PURE__ */ jsx68(Text, { color, children: indicator }),
@@ -32632,9 +32865,9 @@ function Banner({
32632
32865
  Math.max(1, panelWidth - (unbordered ? 0 : 4))
32633
32866
  );
32634
32867
  if (unbordered) {
32635
- return /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE, bold: true, children: summary });
32868
+ return /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE2, bold: true, children: summary });
32636
32869
  }
32637
- return /* @__PURE__ */ jsx68(Box, { width: panelWidth, borderStyle: "round", borderColor: BORDER, paddingX: 1, children: /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE, bold: true, children: summary }) });
32870
+ return /* @__PURE__ */ jsx68(Box, { width: panelWidth, borderStyle: "round", borderColor: BORDER, paddingX: 1, children: /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE2, bold: true, children: summary }) });
32638
32871
  }
32639
32872
  return /* @__PURE__ */ jsxs66(
32640
32873
  Box,
@@ -32651,7 +32884,7 @@ function Banner({
32651
32884
  "v",
32652
32885
  version
32653
32886
  ] }),
32654
- entry.updateAvailable && entry.latestVersion ? /* @__PURE__ */ jsxs66(Text, { color: STACK_ORANGE, children: [
32887
+ entry.updateAvailable && entry.latestVersion ? /* @__PURE__ */ jsxs66(Text, { color: STACK_ORANGE2, children: [
32655
32888
  " \xB7 (update available: v",
32656
32889
  entry.latestVersion,
32657
32890
  ")"
@@ -33597,9 +33830,9 @@ var History = memo2(function History2({
33597
33830
  ] });
33598
33831
  });
33599
33832
 
33600
- // src/components/scrollable-history.tsx
33601
- import { jsx as jsx72, jsxs as jsxs70 } from "react/jsx-runtime";
33833
+ // src/components/history/copy-geometry.ts
33602
33834
  var LIVE_TOOL_STREAM_COPY_ID = -1;
33835
+ var SELECTION_COPY_ID = -2;
33603
33836
  function findCopyHit(hits, row, col) {
33604
33837
  for (let i = hits.length - 1; i >= 0; i--) {
33605
33838
  const hit = hits[i];
@@ -33629,7 +33862,8 @@ function copyRegistryVisibleClip(opts) {
33629
33862
  return Math.max(0, opts.mountedRows + opts.tailRows - opts.viewportRows);
33630
33863
  }
33631
33864
  function liveToolStreamCopyHit(opts) {
33632
- const headerRow = opts.mountedRows - opts.visibleClip + 1;
33865
+ const slack = opts.pinnedSlack ?? 0;
33866
+ const headerRow = opts.mountedRows - opts.visibleClip + 1 + slack;
33633
33867
  if (!opts.visible || headerRow < 0 || headerRow >= opts.viewportRows) return null;
33634
33868
  return {
33635
33869
  entryId: LIVE_TOOL_STREAM_COPY_ID,
@@ -33638,7 +33872,104 @@ function liveToolStreamCopyHit(opts) {
33638
33872
  iconCol: opts.iconCol
33639
33873
  };
33640
33874
  }
33641
- function buildCopyRegistry(opts) {
33875
+
33876
+ // src/components/history/selection-helpers.ts
33877
+ function normalizeSelection(a, b, inProgress) {
33878
+ const topLeft = { row: Math.min(a.row, b.row), col: Math.min(a.col, b.col) };
33879
+ const bottomRight = { row: Math.max(a.row, b.row), col: Math.max(a.col, b.col) };
33880
+ return { topLeft, bottomRight, inProgress };
33881
+ }
33882
+ function isOutOfBand(col, termWidth) {
33883
+ return col < 0 || col >= termWidth;
33884
+ }
33885
+ function selectionToSlices(opts) {
33886
+ const { selection, cards, cardVisibleCols } = opts;
33887
+ const maxCol = Math.max(0, cardVisibleCols - 1);
33888
+ const result = [];
33889
+ for (const card of cards) {
33890
+ const visTop = Math.max(selection.topLeft.row, card.viewportStartRow);
33891
+ const visBot = Math.min(selection.bottomRight.row, card.viewportEndRow - 1);
33892
+ if (visTop > visBot) continue;
33893
+ const entryStartRow = visTop - card.viewportStartRow;
33894
+ const entryEndRow = visBot - card.viewportStartRow;
33895
+ const startCol = entryStartRow === selection.topLeft.row - card.viewportStartRow ? Math.max(0, Math.min(maxCol, selection.topLeft.col)) : 0;
33896
+ const endCol = entryEndRow === selection.bottomRight.row - card.viewportStartRow ? Math.max(startCol, Math.min(maxCol, selection.bottomRight.col)) : maxCol;
33897
+ result.push({
33898
+ entryId: card.entryId,
33899
+ startRow: entryStartRow,
33900
+ startCol,
33901
+ endRow: entryEndRow,
33902
+ endCol
33903
+ });
33904
+ }
33905
+ return result;
33906
+ }
33907
+ function assembleSelectionText(opts) {
33908
+ const { slices, entriesById, toolGroupsByHeadId } = opts;
33909
+ if (slices.length === 0) return "";
33910
+ const byEntry = /* @__PURE__ */ new Map();
33911
+ for (const slice of slices) {
33912
+ const list = byEntry.get(slice.entryId);
33913
+ if (list) list.push(slice);
33914
+ else byEntry.set(slice.entryId, [slice]);
33915
+ }
33916
+ const segments = [];
33917
+ let toolGroupCount = 0;
33918
+ for (const [entryId, entrySlices] of byEntry) {
33919
+ const head = entriesById.get(entryId);
33920
+ if (!head) continue;
33921
+ const groupMembers = toolGroupsByHeadId?.get(entryId);
33922
+ const entries = groupMembers && groupMembers.length > 1 ? groupMembers.map((id) => entriesById.get(id)).filter((entry) => entry !== void 0) : [head];
33923
+ if (entries.length === 0) continue;
33924
+ if (entries.length > 1) toolGroupCount += 1;
33925
+ const fullText = entries.length === 1 ? copyableTextForEntry(entries[0]) : copyableTextForEntries(entries);
33926
+ if (fullText.length === 0) continue;
33927
+ if (entries.length > 1) {
33928
+ segments.push(fullText);
33929
+ continue;
33930
+ }
33931
+ for (const slice of entrySlices) {
33932
+ const rows = fullText.split("\n");
33933
+ const collected = [];
33934
+ for (let r = slice.startRow; r <= slice.endRow && r < rows.length; r++) {
33935
+ const line = rows[r] ?? "";
33936
+ if (slice.startRow === slice.endRow) {
33937
+ const start = Math.max(0, Math.min(line.length, slice.startCol));
33938
+ const end = Math.max(start, Math.min(line.length, slice.endCol + 1));
33939
+ if (end > start) collected.push(line.slice(start, end));
33940
+ } else if (r === slice.startRow) {
33941
+ const start = Math.max(0, Math.min(line.length, slice.startCol));
33942
+ if (start < line.length) collected.push(line.slice(start));
33943
+ } else if (r === slice.endRow) {
33944
+ const end = Math.max(0, Math.min(line.length, slice.endCol + 1));
33945
+ if (end > 0) collected.push(line.slice(0, end));
33946
+ } else {
33947
+ collected.push(line);
33948
+ }
33949
+ }
33950
+ const seg = collected.join("\n");
33951
+ if (seg.length > 0) segments.push(seg);
33952
+ }
33953
+ }
33954
+ if (segments.length === 0) return "";
33955
+ const separator = byEntry.size > 1 || toolGroupCount > 0 ? "\n---\n" : "\n";
33956
+ return segments.join(separator);
33957
+ }
33958
+
33959
+ // src/components/history/scrollbar-geometry.ts
33960
+ function scrollbarThumb(rows, offset, total) {
33961
+ const scrollable = total > rows;
33962
+ if (!scrollable) return { top: 0, size: rows, scrollable: false };
33963
+ const windowTop = Math.max(0, total - rows - offset);
33964
+ const size = Math.max(1, Math.round(rows / total * rows));
33965
+ const maxWindowTop = total - rows;
33966
+ const top = Math.max(
33967
+ 0,
33968
+ Math.min(rows - size, Math.round(windowTop / maxWindowTop * (rows - size)))
33969
+ );
33970
+ return { top, size, scrollable: true };
33971
+ }
33972
+ function buildMountedCardSpans(opts) {
33642
33973
  const mountedGroupRows = opts.renderGroups.reduce(
33643
33974
  (rows, group) => rows + (opts.heightCache.getHeight(renderGroupId(group)) ?? 0),
33644
33975
  0
@@ -33650,47 +33981,40 @@ function buildCopyRegistry(opts) {
33650
33981
  tailRows: opts.tailRows,
33651
33982
  viewportRows: opts.viewportRows
33652
33983
  });
33653
- const hits = [];
33984
+ const spans = [];
33654
33985
  let offset = 0;
33986
+ const pinnedSlack = !opts.scrolled ? Math.max(0, opts.viewportRows - mountedGroupRows - opts.tailRows) : 0;
33655
33987
  for (const group of opts.renderGroups) {
33656
33988
  const gid = renderGroupId(group);
33657
33989
  const groupHeight = opts.heightCache.getHeight(gid) ?? 0;
33658
- const startRow = offset - visibleClip;
33990
+ const viewportStartRow = offset - visibleClip + pinnedSlack;
33659
33991
  offset += groupHeight;
33660
- const groupEntryIds = group.type === "tool-group" ? group.data.entries.map((entry) => entry.id) : isCopyableEntry(group.entry) && !(group.entry.kind === "thinking" && opts.showModelReasoning === false) ? [group.entry.id] : [];
33661
- const entryId = groupEntryIds[0];
33662
- if (entryId === void 0 || startRow < 0 || startRow >= opts.viewportRows) continue;
33663
- hits.push({
33992
+ const entryIds = group.type === "tool-group" ? group.data.entries.map((entry) => entry.id) : isCopyableEntry(group.entry) && !(group.entry.kind === "thinking" && opts.showModelReasoning === false) ? [group.entry.id] : [];
33993
+ const entryId = entryIds[0];
33994
+ if (entryId === void 0) continue;
33995
+ const viewportEndRow = viewportStartRow + groupHeight;
33996
+ if (viewportEndRow <= 0 || viewportStartRow >= opts.viewportRows) continue;
33997
+ spans.push({
33664
33998
  entryId,
33665
- ...groupEntryIds.length > 1 ? { entryIds: groupEntryIds } : {},
33666
- startRow,
33667
- endRow: startRow + 1,
33668
- iconCol: opts.iconCol
33999
+ viewportStartRow,
34000
+ viewportEndRow,
34001
+ totalRows: groupHeight,
34002
+ ...entryIds.length > 1 ? { entryIds } : {}
33669
34003
  });
33670
34004
  }
33671
- return {
33672
- hits,
33673
- liveHit: liveToolStreamCopyHit({
33674
- visible: opts.liveToolVisible,
33675
- mountedRows: mountedGroupRows,
33676
- visibleClip,
33677
- viewportRows: opts.viewportRows,
33678
- iconCol: opts.iconCol
33679
- })
33680
- };
34005
+ return spans;
33681
34006
  }
33682
- function scrollbarThumb(rows, offset, total) {
33683
- const scrollable = total > rows;
33684
- if (!scrollable) return { top: 0, size: rows, scrollable: false };
33685
- const windowTop = Math.max(0, total - rows - offset);
33686
- const size = Math.max(1, Math.round(rows / total * rows));
33687
- const maxWindowTop = total - rows;
33688
- const top = Math.max(
33689
- 0,
33690
- Math.min(rows - size, Math.round(windowTop / maxWindowTop * (rows - size)))
33691
- );
33692
- return { top, size, scrollable: true };
34007
+ function selectionHitAt(row, spans) {
34008
+ for (const span of spans) {
34009
+ if (row >= span.viewportStartRow && row < span.viewportEndRow) {
34010
+ return { entryId: span.entryId, ...span.entryIds ? { entryIds: span.entryIds } : {} };
34011
+ }
34012
+ }
34013
+ return null;
33693
34014
  }
34015
+
34016
+ // src/components/history/scrollbar-rail.tsx
34017
+ import { jsx as jsx72, jsxs as jsxs70 } from "react/jsx-runtime";
33694
34018
  function Scrollbar({
33695
34019
  rows,
33696
34020
  offset,
@@ -33715,6 +34039,7 @@ function Scrollbar({
33715
34039
  children: copyHit ? COPY_ICON : " "
33716
34040
  }
33717
34041
  ),
34042
+ /* @__PURE__ */ jsx72(Text, { children: " " }),
33718
34043
  /* @__PURE__ */ jsx72(
33719
34044
  Text,
33720
34045
  {
@@ -33726,6 +34051,52 @@ function Scrollbar({
33726
34051
  ] }, row);
33727
34052
  }) });
33728
34053
  }
34054
+
34055
+ // src/components/scrollable-history.tsx
34056
+ import { jsx as jsx73, jsxs as jsxs71 } from "react/jsx-runtime";
34057
+ function buildCopyRegistry(opts) {
34058
+ const mountedGroupRows = opts.renderGroups.reduce(
34059
+ (rows, group) => rows + (opts.heightCache.getHeight(renderGroupId(group)) ?? 0),
34060
+ 0
34061
+ );
34062
+ const visibleClip = copyRegistryVisibleClip({
34063
+ scrolled: opts.scrolled,
34064
+ clip: opts.clip,
34065
+ mountedRows: mountedGroupRows,
34066
+ tailRows: opts.tailRows,
34067
+ viewportRows: opts.viewportRows
34068
+ });
34069
+ const pinnedSlack = !opts.scrolled ? Math.max(0, opts.viewportRows - mountedGroupRows - opts.tailRows) : 0;
34070
+ const hits = [];
34071
+ let offset = 0;
34072
+ for (const group of opts.renderGroups) {
34073
+ const gid = renderGroupId(group);
34074
+ const groupHeight = opts.heightCache.getHeight(gid) ?? 0;
34075
+ const startRow = offset - visibleClip + pinnedSlack;
34076
+ offset += groupHeight;
34077
+ const groupEntryIds = group.type === "tool-group" ? group.data.entries.map((entry) => entry.id) : isCopyableEntry(group.entry) && !(group.entry.kind === "thinking" && opts.showModelReasoning === false) ? [group.entry.id] : [];
34078
+ const entryId = groupEntryIds[0];
34079
+ if (entryId === void 0 || startRow < 0 || startRow >= opts.viewportRows) continue;
34080
+ hits.push({
34081
+ entryId,
34082
+ ...groupEntryIds.length > 1 ? { entryIds: groupEntryIds } : {},
34083
+ startRow,
34084
+ endRow: startRow + 1,
34085
+ iconCol: opts.iconCol
34086
+ });
34087
+ }
34088
+ return {
34089
+ hits,
34090
+ liveHit: liveToolStreamCopyHit({
34091
+ visible: opts.liveToolVisible,
34092
+ mountedRows: mountedGroupRows,
34093
+ visibleClip,
34094
+ viewportRows: opts.viewportRows,
34095
+ iconCol: opts.iconCol,
34096
+ pinnedSlack
34097
+ })
34098
+ };
34099
+ }
33729
34100
  var UNDERFILL_BUMP_ROWS = 16;
33730
34101
  var MAX_UNDERFILL_BUMPS = 8;
33731
34102
  var ScrollableHistory = memo3(function ScrollableHistory2({
@@ -33759,6 +34130,7 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
33759
34130
  const handleResize = () => {
33760
34131
  setViewportWidth(resolveViewportWidth());
33761
34132
  };
34133
+ handleResize();
33762
34134
  stdout?.on("resize", handleResize);
33763
34135
  return () => {
33764
34136
  stdout?.off("resize", handleResize);
@@ -33776,6 +34148,9 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
33776
34148
  const measuredGroupIdsRef = useRef37(/* @__PURE__ */ new Set());
33777
34149
  const copyHitsRef = useRef37([]);
33778
34150
  const liveToolCopyHitRef = useRef37(null);
34151
+ const mountedGroupSpansRef = useRef37([]);
34152
+ const spansSignatureRef = useRef37("");
34153
+ const selectionRef = useRef37({ anchor: null, head: null, inProgress: false });
33779
34154
  const toolStreamRef = useRef37(toolStream);
33780
34155
  toolStreamRef.current = toolStream;
33781
34156
  const entriesByIdRef = useRef37(/* @__PURE__ */ new Map());
@@ -33891,6 +34266,7 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
33891
34266
  const ids = groupIdsRef.current;
33892
34267
  const nextId = next ? ids[next.index] : void 0;
33893
34268
  const normalized = next && nextId !== void 0 ? { index: next.index, clip: Math.max(0, next.clip) } : null;
34269
+ selectionRef.current = { anchor: null, head: null, inProgress: false };
33894
34270
  effectiveAnchorRef.current = normalized;
33895
34271
  setAnchor(normalized && nextId !== void 0 ? { id: nextId, clip: normalized.clip } : null);
33896
34272
  setMountBump(0);
@@ -33936,9 +34312,77 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
33936
34312
  );
33937
34313
  if (payload === null) return null;
33938
34314
  return await writeClipboardText(payload.text) ? payload.entryId : null;
34315
+ },
34316
+ beginSelection: (row, col) => {
34317
+ if (isOutOfBand(col, termWidth)) {
34318
+ selectionRef.current = { anchor: null, head: null, inProgress: false };
34319
+ return;
34320
+ }
34321
+ const cardHit = selectionHitAt(row, mountedGroupSpansRef.current);
34322
+ if (cardHit === null) {
34323
+ selectionRef.current = { anchor: null, head: null, inProgress: false };
34324
+ return;
34325
+ }
34326
+ selectionRef.current = {
34327
+ anchor: { row, col },
34328
+ head: { row, col },
34329
+ inProgress: true
34330
+ };
34331
+ },
34332
+ extendSelection: (row, col) => {
34333
+ const cur = selectionRef.current;
34334
+ if (cur.anchor === null) return;
34335
+ if (cur.inProgress === false) return;
34336
+ if (isOutOfBand(col, termWidth) || row < 0 || row >= vp) {
34337
+ selectionRef.current = { anchor: null, head: null, inProgress: false };
34338
+ return;
34339
+ }
34340
+ selectionRef.current = { ...cur, head: { row, col } };
34341
+ },
34342
+ endSelection: () => {
34343
+ const cur = selectionRef.current;
34344
+ if (cur.anchor === null) return;
34345
+ selectionRef.current = { ...cur, inProgress: false };
34346
+ },
34347
+ clearSelection: () => {
34348
+ const cur = selectionRef.current;
34349
+ if (cur.anchor === null && cur.head === null) return;
34350
+ selectionRef.current = { anchor: null, head: null, inProgress: false };
34351
+ },
34352
+ commitSelection: async () => {
34353
+ const cur = selectionRef.current;
34354
+ if (cur.anchor === null || cur.head === null) return false;
34355
+ if (cur.anchor.row === cur.head.row && cur.anchor.col === cur.head.col) {
34356
+ selectionRef.current = { anchor: null, head: null, inProgress: false };
34357
+ return false;
34358
+ }
34359
+ const rect = normalizeSelection(cur.anchor, cur.head, cur.inProgress);
34360
+ const slices = selectionToSlices({
34361
+ selection: rect,
34362
+ cards: mountedGroupSpansRef.current,
34363
+ cardVisibleCols: termWidth
34364
+ });
34365
+ const toolGroupsByHeadId = /* @__PURE__ */ new Map();
34366
+ for (const span of mountedGroupSpansRef.current) {
34367
+ if (span.entryIds && span.entryIds.length > 1) {
34368
+ toolGroupsByHeadId.set(span.entryId, span.entryIds);
34369
+ }
34370
+ }
34371
+ const text = assembleSelectionText({
34372
+ slices,
34373
+ entriesById: entriesByIdRef.current,
34374
+ ...toolGroupsByHeadId.size > 0 ? { toolGroupsByHeadId } : {}
34375
+ });
34376
+ selectionRef.current = { anchor: null, head: null, inProgress: false };
34377
+ if (text.length === 0) return false;
34378
+ try {
34379
+ return await writeClipboardText(text);
34380
+ } catch {
34381
+ return false;
34382
+ }
33939
34383
  }
33940
34384
  }),
33941
- [applyAnchor]
34385
+ [applyAnchor, termWidth, vp]
33942
34386
  );
33943
34387
  useEffect67(() => {
33944
34388
  if (!controllerRef) return void 0;
@@ -33993,6 +34437,23 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
33993
34437
  copyHitsRef.current = copyRegistry.hits;
33994
34438
  liveToolCopyHitRef.current = copyRegistry.liveHit;
33995
34439
  const copyRailHits = copyRegistry.liveHit ? [...copyRegistry.hits, copyRegistry.liveHit] : copyRegistry.hits;
34440
+ const nextSpans = buildMountedCardSpans({
34441
+ renderGroups,
34442
+ heightCache,
34443
+ scrolled,
34444
+ clip: clip2,
34445
+ tailRows: plan.mountTail ? toolTailHeight : 0,
34446
+ viewportRows: vp,
34447
+ showModelReasoning
34448
+ });
34449
+ const nextSignature = nextSpans.map((s2) => `${s2.entryId}:${s2.viewportStartRow}:${s2.viewportEndRow}`).join("|");
34450
+ if (nextSignature !== spansSignatureRef.current) {
34451
+ if (selectionRef.current.anchor !== null && !selectionRef.current.inProgress) {
34452
+ selectionRef.current = { anchor: null, head: null, inProgress: false };
34453
+ }
34454
+ spansSignatureRef.current = nextSignature;
34455
+ }
34456
+ mountedGroupSpansRef.current = nextSpans;
33996
34457
  useLayoutEffect2(() => {
33997
34458
  let changed = false;
33998
34459
  for (const group of renderGroups) {
@@ -34057,11 +34518,13 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
34057
34518
  }
34058
34519
  if (planStartIdxRef.current > 0) {
34059
34520
  requestOlderFiredRef.current = false;
34521
+ } else if (!scrolled) {
34522
+ requestOlderFiredRef.current = false;
34060
34523
  }
34061
34524
  if (changed) setMeasureTick((tick) => tick + 1);
34062
34525
  });
34063
- return /* @__PURE__ */ jsxs70(Box, { flexDirection: "row", width: viewportWidth, children: [
34064
- /* @__PURE__ */ jsx72(
34526
+ return /* @__PURE__ */ jsxs71(Box, { flexDirection: "row", width: viewportWidth, children: [
34527
+ /* @__PURE__ */ jsx73(
34065
34528
  Box,
34066
34529
  {
34067
34530
  flexDirection: "column",
@@ -34069,7 +34532,7 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
34069
34532
  height: vp,
34070
34533
  overflowY: "hidden",
34071
34534
  justifyContent: scrolled ? "flex-start" : "flex-end",
34072
- children: /* @__PURE__ */ jsxs70(Box, { flexDirection: "column", flexShrink: 0, marginTop: scrolled && clip2 > 0 ? -clip2 : 0, children: [
34535
+ children: /* @__PURE__ */ jsxs71(Box, { flexDirection: "column", flexShrink: 0, marginTop: scrolled && clip2 > 0 ? -clip2 : 0, children: [
34073
34536
  renderGroups.map((group) => {
34074
34537
  const gid = renderGroupId(group);
34075
34538
  const setNode = (node) => {
@@ -34077,15 +34540,15 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
34077
34540
  else entryNodeRefs.current.delete(gid);
34078
34541
  };
34079
34542
  if (group.type === "tool-group") {
34080
- return /* @__PURE__ */ jsx72(Box, { ref: setNode, flexShrink: 0, children: /* @__PURE__ */ jsx72(EntryErrorBoundary, { label: "tool group", resetKey: group.data.entries.length, children: /* @__PURE__ */ jsx72(ToolGroup, { data: group.data, termWidth }) }) }, `tool-group-${gid}`);
34543
+ return /* @__PURE__ */ jsx73(Box, { ref: setNode, flexShrink: 0, children: /* @__PURE__ */ jsx73(EntryErrorBoundary, { label: "tool group", resetKey: group.data.entries.length, children: /* @__PURE__ */ jsx73(ToolGroup, { data: group.data, termWidth }) }) }, `tool-group-${gid}`);
34081
34544
  }
34082
34545
  const { entry } = group;
34083
- const entryEl = /* @__PURE__ */ jsx72(
34546
+ const entryEl = /* @__PURE__ */ jsx73(
34084
34547
  EntryErrorBoundary,
34085
34548
  {
34086
34549
  label: entry.kind,
34087
34550
  resetKey: entry.kind === "tool" ? entry.output?.length ?? 0 : "text" in entry ? entry.text.length : 0,
34088
- children: /* @__PURE__ */ jsx72(
34551
+ children: /* @__PURE__ */ jsx73(
34089
34552
  Entry,
34090
34553
  {
34091
34554
  entry,
@@ -34101,7 +34564,7 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
34101
34564
  )
34102
34565
  }
34103
34566
  );
34104
- return /* @__PURE__ */ jsx72(
34567
+ return /* @__PURE__ */ jsx73(
34105
34568
  Box,
34106
34569
  {
34107
34570
  ref: setNode,
@@ -34112,7 +34575,7 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
34112
34575
  entry.id
34113
34576
  );
34114
34577
  }),
34115
- plan.mountTail && toolTail && toolStream ? /* @__PURE__ */ jsx72(
34578
+ plan.mountTail && toolTail && toolStream ? /* @__PURE__ */ jsx73(
34116
34579
  ToolStreamBox,
34117
34580
  {
34118
34581
  name: toolStream.name,
@@ -34124,7 +34587,7 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
34124
34587
  ] })
34125
34588
  }
34126
34589
  ),
34127
- /* @__PURE__ */ jsx72(
34590
+ /* @__PURE__ */ jsx73(
34128
34591
  Scrollbar,
34129
34592
  {
34130
34593
  rows: vp,
@@ -34137,40 +34600,474 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
34137
34600
  ] });
34138
34601
  });
34139
34602
 
34603
+ // src/components/sidebar.tsx
34604
+ import { jsx as jsx74 } from "react/jsx-runtime";
34605
+ var SIDEBAR_MIN_TERMINAL = 64;
34606
+ var SIDEBAR_MIN_WIDTH = 20;
34607
+ var SIDEBAR_MAX_WIDTH = 48;
34608
+ var SIDEBAR_FRACTION = 0.25;
34609
+ function computeSidebarWidth(termCols) {
34610
+ if (termCols < SIDEBAR_MIN_TERMINAL) return 0;
34611
+ return Math.min(
34612
+ SIDEBAR_MAX_WIDTH,
34613
+ Math.max(SIDEBAR_MIN_WIDTH, Math.floor(termCols * SIDEBAR_FRACTION))
34614
+ );
34615
+ }
34616
+ function RightSidebar({ width, maxHeight, focused = false, children }) {
34617
+ const { stdout } = useStdout();
34618
+ const termCols = stdout?.columns ?? 80;
34619
+ const resolvedWidth = width ?? computeSidebarWidth(termCols);
34620
+ if (resolvedWidth === 0) return null;
34621
+ return /* @__PURE__ */ jsx74(
34622
+ Box,
34623
+ {
34624
+ flexDirection: "column",
34625
+ width: resolvedWidth,
34626
+ height: maxHeight,
34627
+ overflowY: "hidden",
34628
+ flexShrink: 0,
34629
+ borderStyle: focused ? "double" : "round",
34630
+ borderColor: focused ? theme.accent : theme.borderSubtle,
34631
+ paddingX: 1,
34632
+ children: children ?? /* @__PURE__ */ jsx74(Text, { color: theme.textMuted, wrap: "truncate", children: "\u25E7 sidebar" })
34633
+ }
34634
+ );
34635
+ }
34636
+
34637
+ // src/components/sidebar-content.tsx
34638
+ import { Fragment as Fragment26, jsx as jsx75, jsxs as jsxs72 } from "react/jsx-runtime";
34639
+ function trunc2(s2, max) {
34640
+ if (s2.length <= max) return s2;
34641
+ return `${s2.slice(0, Math.max(1, max - 1))}\u2026`;
34642
+ }
34643
+ function statusGlyph(entry) {
34644
+ switch (entry.status) {
34645
+ case "running":
34646
+ return { icon: glyphs.running, color: theme.success };
34647
+ case "idle":
34648
+ return { icon: glyphs.idle, color: theme.textMuted };
34649
+ case "success":
34650
+ return { icon: glyphs.success, color: theme.success };
34651
+ case "failed":
34652
+ case "timeout":
34653
+ case "stopped":
34654
+ return { icon: glyphs.failure, color: theme.error };
34655
+ default:
34656
+ return { icon: "?", color: theme.textMuted };
34657
+ }
34658
+ }
34659
+ function liveSessionIcon(status) {
34660
+ switch (status) {
34661
+ case "active":
34662
+ return "\u25CF";
34663
+ case "idle":
34664
+ return "\u25C9";
34665
+ case "closing":
34666
+ return "\u25D0";
34667
+ case "stale":
34668
+ return "\u25CB";
34669
+ default:
34670
+ return "?";
34671
+ }
34672
+ }
34673
+ function liveSessionColor(status) {
34674
+ if (status === "active" || status === "running") return theme.success;
34675
+ if (status === "idle") return theme.accent;
34676
+ if (status === "error" || status === "stale") return theme.error;
34677
+ if (status === "closing") return theme.warn;
34678
+ return theme.textMuted;
34679
+ }
34680
+ function outcomeBadge(outcome) {
34681
+ switch (outcome) {
34682
+ case "completed":
34683
+ return { label: glyphs.success, color: theme.success };
34684
+ case "error":
34685
+ return { label: glyphs.failure, color: theme.error };
34686
+ case "timeout":
34687
+ return { label: "\u23F1", color: theme.warn };
34688
+ case "aborted":
34689
+ return { label: "\u2298", color: theme.textMuted };
34690
+ default:
34691
+ return null;
34692
+ }
34693
+ }
34694
+ function fmtRelative(iso) {
34695
+ if (!iso) return "";
34696
+ const diff = Date.now() - new Date(iso).getTime();
34697
+ const min = Math.floor(diff / 6e4);
34698
+ if (min < 1) return "now";
34699
+ if (min < 60) return `${min}m`;
34700
+ const h = Math.floor(min / 60);
34701
+ if (h < 24) return `${h}h`;
34702
+ return `${Math.floor(h / 24)}d`;
34703
+ }
34704
+ function SectionHeader({
34705
+ glyph: glyph2,
34706
+ label,
34707
+ color,
34708
+ badge,
34709
+ badgeColor,
34710
+ innerWidth
34711
+ }) {
34712
+ const left = `${glyph2} ${label}`;
34713
+ const leftW = displayWidth(left);
34714
+ const badgeW = badge ? displayWidth(badge) + 1 : 0;
34715
+ const fitsBadge = !!badge && innerWidth - leftW - badgeW >= 0;
34716
+ const fillCount = Math.max(0, innerWidth - leftW - (fitsBadge ? badgeW : 0));
34717
+ return /* @__PURE__ */ jsxs72(Box, { children: [
34718
+ /* @__PURE__ */ jsx75(Text, { color, bold: true, children: left }),
34719
+ /* @__PURE__ */ jsx75(Text, { color: theme.borderSubtle, children: "\xB7".repeat(fillCount) }),
34720
+ fitsBadge ? /* @__PURE__ */ jsxs72(Text, { color: badgeColor ?? color, bold: true, children: [
34721
+ " ",
34722
+ badge
34723
+ ] }) : null
34724
+ ] });
34725
+ }
34726
+ function Card({
34727
+ innerWidth,
34728
+ marginBottom = 1,
34729
+ children
34730
+ }) {
34731
+ return /* @__PURE__ */ jsx75(
34732
+ Box,
34733
+ {
34734
+ flexDirection: "column",
34735
+ width: innerWidth,
34736
+ marginBottom,
34737
+ ...theme.supportsBackground ? { backgroundColor: theme.surfaceRaised } : {},
34738
+ children
34739
+ }
34740
+ );
34741
+ }
34742
+ function buildMissionRows(todos, maxRows, textWidth) {
34743
+ const list = todos ?? [];
34744
+ const total = list.length;
34745
+ const done = list.filter((t) => t.status === "completed").length;
34746
+ if (total === 0 || maxRows <= 0) return { rows: [], overflow: 0, done, total };
34747
+ const rank = (t) => t.status === "in_progress" ? 0 : t.status === "pending" ? 1 : 2;
34748
+ const ordered = [...list].sort((a, b) => rank(a) - rank(b));
34749
+ const shown = ordered.slice(0, maxRows);
34750
+ const rows = shown.map((t) => ({
34751
+ id: t.id,
34752
+ status: t.status,
34753
+ label: trunc2(
34754
+ t.status === "in_progress" && t.activeForm ? t.activeForm : t.content,
34755
+ textWidth
34756
+ )
34757
+ }));
34758
+ return { rows, overflow: ordered.length - shown.length, done, total };
34759
+ }
34760
+ function SidebarContent({
34761
+ contextWindow,
34762
+ entries,
34763
+ fleetCounts,
34764
+ provider,
34765
+ model,
34766
+ width,
34767
+ scrollOffset = 0,
34768
+ focused = false,
34769
+ todos,
34770
+ showSwarmSection = false,
34771
+ liveSessions,
34772
+ resumeSessions,
34773
+ currentSessionId
34774
+ }) {
34775
+ const innerWidth = Math.max(8, width - 4);
34776
+ const ctxRatio = contextWindow ? Math.min(1, contextWindow.used / contextWindow.max) : 0;
34777
+ const ctxColor = contextBarColor(ctxRatio);
34778
+ const ctxPct = Math.round(ctxRatio * 100);
34779
+ const meter = blockMeter(ctxRatio, innerWidth);
34780
+ const MAX_SIDEBAR_AGENTS = 12;
34781
+ const allEntries = Object.values(entries);
34782
+ const leader = allEntries.find(
34783
+ (e) => e.id === "leader" || e.name === "Leader Agent"
34784
+ );
34785
+ const subagents = allEntries.filter((e) => e !== leader);
34786
+ const runningSubagents = subagents.filter((e) => e.status === "running");
34787
+ const agentCap = leader ? MAX_SIDEBAR_AGENTS - 1 : MAX_SIDEBAR_AGENTS;
34788
+ const shownAgents = [
34789
+ ...leader ? [leader] : [],
34790
+ ...runningSubagents.slice(0, agentCap)
34791
+ ];
34792
+ const hiddenAgentCount = runningSubagents.length - agentCap;
34793
+ const running = fleetCounts?.running ?? runningSubagents.length;
34794
+ const mission = showSwarmSection ? buildMissionRows(todos, SIDEBAR_MISSION_ROWS, innerWidth - 3) : { rows: [], overflow: 0, done: 0, total: 0 };
34795
+ return /* @__PURE__ */ jsxs72(
34796
+ Box,
34797
+ {
34798
+ flexDirection: "column",
34799
+ gap: 0,
34800
+ marginTop: scrollOffset > 0 ? -scrollOffset : void 0,
34801
+ children: [
34802
+ focused ? /* @__PURE__ */ jsxs72(Box, { width: innerWidth, marginBottom: 1, children: [
34803
+ /* @__PURE__ */ jsx75(Text, { color: theme.accent, bold: true, children: "\u2191\u2193" }),
34804
+ /* @__PURE__ */ jsx75(Text, { color: theme.textMuted, children: " scroll \xB7 Shift+Tab exits" })
34805
+ ] }) : null,
34806
+ /* @__PURE__ */ jsxs72(Card, { innerWidth, children: [
34807
+ /* @__PURE__ */ jsx75(
34808
+ SectionHeader,
34809
+ {
34810
+ glyph: glyphs.context,
34811
+ label: "CONTEXT",
34812
+ color: pastel.peach,
34813
+ badge: contextWindow ? `${ctxPct}%` : "\u2014",
34814
+ badgeColor: ctxColor,
34815
+ innerWidth
34816
+ }
34817
+ ),
34818
+ contextWindow ? /* @__PURE__ */ jsxs72(Fragment26, { children: [
34819
+ /* @__PURE__ */ jsxs72(Box, { children: [
34820
+ /* @__PURE__ */ jsx75(Text, { color: ctxColor, children: meter.filled }),
34821
+ /* @__PURE__ */ jsx75(Text, { color: theme.borderSubtle, children: meter.empty })
34822
+ ] }),
34823
+ /* @__PURE__ */ jsxs72(Text, { color: theme.textMuted, wrap: "truncate", children: [
34824
+ fmtTok(contextWindow.used),
34825
+ " / ",
34826
+ fmtTok(contextWindow.max),
34827
+ " tokens"
34828
+ ] })
34829
+ ] }) : /* @__PURE__ */ jsx75(Text, { color: theme.textMuted, children: "\u2014" })
34830
+ ] }),
34831
+ provider && model ? /* @__PURE__ */ jsxs72(Card, { innerWidth, children: [
34832
+ /* @__PURE__ */ jsx75(
34833
+ SectionHeader,
34834
+ {
34835
+ glyph: glyphs.tools,
34836
+ label: "MODEL",
34837
+ color: theme.brand,
34838
+ innerWidth
34839
+ }
34840
+ ),
34841
+ /* @__PURE__ */ jsx75(Text, { color: theme.textSecondary, wrap: "truncate", children: trunc2(`${provider}/${model}`, innerWidth) })
34842
+ ] }) : null,
34843
+ /* @__PURE__ */ jsxs72(Card, { innerWidth, marginBottom: shownAgents.length > 0 ? 0 : 1, children: [
34844
+ /* @__PURE__ */ jsx75(
34845
+ SectionHeader,
34846
+ {
34847
+ glyph: glyphs.fleet,
34848
+ label: "AGENT SWARM",
34849
+ color: theme.monitor.fleet,
34850
+ badge: running > 0 ? `${running} LIVE` : "IDLE",
34851
+ badgeColor: running > 0 ? theme.success : theme.textMuted,
34852
+ innerWidth
34853
+ }
34854
+ ),
34855
+ running > 0 ? /* @__PURE__ */ jsxs72(Box, { children: [
34856
+ /* @__PURE__ */ jsx75(Text, { color: theme.success, children: glyphs.running }),
34857
+ /* @__PURE__ */ jsxs72(Text, { color: theme.textSecondary, wrap: "truncate", children: [
34858
+ " ",
34859
+ running,
34860
+ " running"
34861
+ ] })
34862
+ ] }) : /* @__PURE__ */ jsxs72(Box, { children: [
34863
+ /* @__PURE__ */ jsx75(Text, { color: theme.textMuted, children: glyphs.pending }),
34864
+ /* @__PURE__ */ jsx75(Text, { color: theme.textMuted, children: " idle" })
34865
+ ] })
34866
+ ] }),
34867
+ shownAgents.length > 0 ? /* @__PURE__ */ jsxs72(Box, { flexDirection: "column", width: innerWidth, marginBottom: 1, children: [
34868
+ shownAgents.map((entry) => {
34869
+ const { icon, color } = statusGlyph(entry);
34870
+ const isRunning = entry.status === "running";
34871
+ const name = trunc2(entry.name || entry.id, innerWidth - 6);
34872
+ const ctxPctAgent = entry.ctxPct != null ? `${Math.round(entry.ctxPct * 100)}%` : "";
34873
+ const statusLabel = entry.status === "running" ? "running" : entry.status === "idle" ? "idle" : entry.status;
34874
+ const tool = entry.currentTool?.name ? trunc2(entry.currentTool.name, innerWidth - statusLabel.length - 4) : "";
34875
+ return /* @__PURE__ */ jsxs72(Box, { flexDirection: "column", marginBottom: 0, children: [
34876
+ /* @__PURE__ */ jsxs72(Box, { flexDirection: "row", children: [
34877
+ /* @__PURE__ */ jsxs72(Text, { color, children: [
34878
+ icon,
34879
+ " "
34880
+ ] }),
34881
+ /* @__PURE__ */ jsx75(
34882
+ Text,
34883
+ {
34884
+ color: isRunning ? theme.textPrimary : theme.textSecondary,
34885
+ bold: isRunning,
34886
+ wrap: "truncate",
34887
+ children: name
34888
+ }
34889
+ ),
34890
+ ctxPctAgent ? /* @__PURE__ */ jsxs72(
34891
+ Text,
34892
+ {
34893
+ color: entry.ctxPct != null ? contextBarColor(entry.ctxPct) : theme.textMuted,
34894
+ children: [
34895
+ " ",
34896
+ ctxPctAgent
34897
+ ]
34898
+ }
34899
+ ) : null
34900
+ ] }),
34901
+ /* @__PURE__ */ jsxs72(Box, { flexDirection: "row", children: [
34902
+ /* @__PURE__ */ jsx75(Text, { color, children: " " }),
34903
+ /* @__PURE__ */ jsxs72(Text, { color: theme.textMuted, wrap: "truncate", children: [
34904
+ statusLabel,
34905
+ tool ? ` \xB7 ${tool}` : ""
34906
+ ] })
34907
+ ] })
34908
+ ] }, entry.id);
34909
+ }),
34910
+ hiddenAgentCount > 0 ? /* @__PURE__ */ jsxs72(Text, { color: theme.textMuted, children: [
34911
+ " +",
34912
+ hiddenAgentCount,
34913
+ " more"
34914
+ ] }) : null
34915
+ ] }) : null,
34916
+ mission.total > 0 ? /* @__PURE__ */ jsxs72(Card, { innerWidth, children: [
34917
+ /* @__PURE__ */ jsx75(
34918
+ SectionHeader,
34919
+ {
34920
+ glyph: glyphs.queue,
34921
+ label: "MISSIONS",
34922
+ color: theme.warn,
34923
+ badge: `${mission.done}/${mission.total}`,
34924
+ badgeColor: mission.done === mission.total ? theme.success : theme.warn,
34925
+ innerWidth
34926
+ }
34927
+ ),
34928
+ mission.rows.map((m) => {
34929
+ if (m.status === "completed") {
34930
+ return /* @__PURE__ */ jsxs72(Box, { children: [
34931
+ /* @__PURE__ */ jsxs72(Text, { color: theme.success, children: [
34932
+ glyphs.success,
34933
+ " "
34934
+ ] }),
34935
+ /* @__PURE__ */ jsx75(Text, { color: theme.textMuted, dimColor: true, strikethrough: true, wrap: "truncate", children: m.label })
34936
+ ] }, m.id);
34937
+ }
34938
+ if (m.status === "in_progress") {
34939
+ return /* @__PURE__ */ jsxs72(Box, { children: [
34940
+ /* @__PURE__ */ jsxs72(Text, { color: theme.accent, children: [
34941
+ glyphs.running,
34942
+ " "
34943
+ ] }),
34944
+ /* @__PURE__ */ jsx75(Text, { color: theme.textPrimary, bold: true, wrap: "truncate", children: m.label })
34945
+ ] }, m.id);
34946
+ }
34947
+ return /* @__PURE__ */ jsxs72(Box, { children: [
34948
+ /* @__PURE__ */ jsxs72(Text, { color: theme.textMuted, children: [
34949
+ glyphs.pending,
34950
+ " "
34951
+ ] }),
34952
+ /* @__PURE__ */ jsx75(Text, { color: theme.textSecondary, wrap: "truncate", children: m.label })
34953
+ ] }, m.id);
34954
+ }),
34955
+ mission.overflow > 0 ? /* @__PURE__ */ jsxs72(Text, { color: theme.textMuted, dimColor: true, children: [
34956
+ " ",
34957
+ "+",
34958
+ mission.overflow,
34959
+ " more"
34960
+ ] }) : null
34961
+ ] }) : null,
34962
+ (liveSessions?.length ?? 0) > 0 || (resumeSessions?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs72(Card, { innerWidth, marginBottom: 0, children: [
34963
+ /* @__PURE__ */ jsx75(
34964
+ SectionHeader,
34965
+ {
34966
+ glyph: glyphs.sessions,
34967
+ label: "SESSIONS",
34968
+ color: theme.success,
34969
+ badge: String((liveSessions?.length ?? 0) + (resumeSessions?.length ?? 0)),
34970
+ badgeColor: theme.textSecondary,
34971
+ innerWidth
34972
+ }
34973
+ ),
34974
+ liveSessions && liveSessions.length > 0 ? /* @__PURE__ */ jsx75(Box, { flexDirection: "column", children: liveSessions.slice(0, 3).map((s2) => {
34975
+ const isCurrent = s2.sessionId === currentSessionId;
34976
+ const icon = isCurrent ? "\u25CF" : liveSessionIcon(s2.status);
34977
+ const color = liveSessionColor(s2.status);
34978
+ const name = trunc2(s2.projectName, innerWidth - 6);
34979
+ const agents = s2.agentCount > 0 ? ` ${s2.agentCount}a` : "";
34980
+ return /* @__PURE__ */ jsxs72(Box, { flexDirection: "row", children: [
34981
+ /* @__PURE__ */ jsxs72(Text, { color, children: [
34982
+ icon,
34983
+ " "
34984
+ ] }),
34985
+ /* @__PURE__ */ jsx75(
34986
+ Text,
34987
+ {
34988
+ color: isCurrent ? theme.accent : theme.textSecondary,
34989
+ wrap: "truncate",
34990
+ bold: isCurrent,
34991
+ children: name
34992
+ }
34993
+ ),
34994
+ /* @__PURE__ */ jsx75(Text, { color: theme.textMuted, children: agents })
34995
+ ] }, s2.sessionId);
34996
+ }) }) : null,
34997
+ resumeSessions && resumeSessions.length > 0 ? /* @__PURE__ */ jsx75(
34998
+ Box,
34999
+ {
35000
+ flexDirection: "column",
35001
+ marginTop: liveSessions && liveSessions.length > 0 ? 1 : 0,
35002
+ children: resumeSessions.slice(0, 3).map((rs) => {
35003
+ const badge = outcomeBadge(rs.outcome);
35004
+ const title = trunc2(
35005
+ rs.title || rs.lastUserMessage || rs.id,
35006
+ innerWidth - 8
35007
+ );
35008
+ const rel = fmtRelative(rs.lastActivityAt ?? rs.endedAt);
35009
+ return /* @__PURE__ */ jsxs72(Box, { flexDirection: "row", children: [
35010
+ /* @__PURE__ */ jsxs72(Text, { color: badge ? badge.color : theme.textMuted, children: [
35011
+ badge ? badge.label : "\xB7",
35012
+ " "
35013
+ ] }),
35014
+ /* @__PURE__ */ jsx75(
35015
+ Text,
35016
+ {
35017
+ color: rs.isCurrent ? theme.accent : theme.textSecondary,
35018
+ wrap: "truncate",
35019
+ ...rs.isCurrent ? { bold: true } : {},
35020
+ children: title
35021
+ }
35022
+ ),
35023
+ rel ? /* @__PURE__ */ jsxs72(Text, { color: theme.textMuted, children: [
35024
+ " ",
35025
+ rel
35026
+ ] }) : null
35027
+ ] }, rs.id);
35028
+ })
35029
+ }
35030
+ ) : null
35031
+ ] }) : null
35032
+ ]
35033
+ }
35034
+ );
35035
+ }
35036
+
34140
35037
  // src/components/shadow-panel.tsx
34141
- import { jsx as jsx73, jsxs as jsxs71 } from "react/jsx-runtime";
35038
+ import { jsx as jsx76, jsxs as jsxs73 } from "react/jsx-runtime";
34142
35039
  function ShadowPanel({
34143
35040
  shadow,
34144
35041
  hint
34145
35042
  }) {
34146
- return /* @__PURE__ */ jsxs71(Box, { flexDirection: "column", borderStyle: "round", borderColor: "blue", paddingX: 1, children: [
34147
- /* @__PURE__ */ jsx73(Text, { bold: true, color: "blue", children: "\u2501\u2501 Shadow Agent \u2501\u2501" }),
34148
- /* @__PURE__ */ jsx73(Text, { dimColor: true, children: "s start \xB7 t stop \xB7 i cycle interval \xB7 m cycle model \xB7 Esc close" }),
34149
- /* @__PURE__ */ jsxs71(Box, { marginTop: 1, flexDirection: "column", children: [
34150
- /* @__PURE__ */ jsxs71(Box, { children: [
34151
- /* @__PURE__ */ jsx73(Text, { bold: true, children: "Status: " }),
34152
- shadow.running ? /* @__PURE__ */ jsx73(Text, { color: "green", children: "\u25CF running" }) : /* @__PURE__ */ jsx73(Text, { color: "gray", children: "\u25CB stopped" }),
34153
- shadow.activeId ? /* @__PURE__ */ jsx73(Text, { dimColor: true, children: ` ${shadow.activeId.slice(0, 12)}\u2026` }) : null
35043
+ return /* @__PURE__ */ jsxs73(Box, { flexDirection: "column", borderStyle: "round", borderColor: "blue", paddingX: 1, children: [
35044
+ /* @__PURE__ */ jsx76(Text, { bold: true, color: "blue", children: "\u2501\u2501 Shadow Agent \u2501\u2501" }),
35045
+ /* @__PURE__ */ jsx76(Text, { dimColor: true, children: "s start \xB7 t stop \xB7 i cycle interval \xB7 m cycle model \xB7 Esc close" }),
35046
+ /* @__PURE__ */ jsxs73(Box, { marginTop: 1, flexDirection: "column", children: [
35047
+ /* @__PURE__ */ jsxs73(Box, { children: [
35048
+ /* @__PURE__ */ jsx76(Text, { bold: true, children: "Status: " }),
35049
+ shadow.running ? /* @__PURE__ */ jsx76(Text, { color: "green", children: "\u25CF running" }) : /* @__PURE__ */ jsx76(Text, { color: "gray", children: "\u25CB stopped" }),
35050
+ shadow.activeId ? /* @__PURE__ */ jsx76(Text, { dimColor: true, children: ` ${shadow.activeId.slice(0, 12)}\u2026` }) : null
34154
35051
  ] }),
34155
- /* @__PURE__ */ jsxs71(Box, { marginTop: 1, children: [
34156
- /* @__PURE__ */ jsx73(Text, { bold: true, children: "Model: " }),
34157
- /* @__PURE__ */ jsx73(Text, { color: "cyan", children: shadow.model })
35052
+ /* @__PURE__ */ jsxs73(Box, { marginTop: 1, children: [
35053
+ /* @__PURE__ */ jsx76(Text, { bold: true, children: "Model: " }),
35054
+ /* @__PURE__ */ jsx76(Text, { color: "cyan", children: shadow.model })
34158
35055
  ] }),
34159
- /* @__PURE__ */ jsxs71(Box, { marginTop: 1, children: [
34160
- /* @__PURE__ */ jsx73(Text, { bold: true, children: "Interval: " }),
34161
- /* @__PURE__ */ jsx73(Text, { color: "yellow", children: shadow.intervalMs >= 1e3 ? `${shadow.intervalMs / 1e3}s` : `${shadow.intervalMs}ms` }),
34162
- /* @__PURE__ */ jsx73(Text, { dimColor: true, children: " (min 5s)" })
35056
+ /* @__PURE__ */ jsxs73(Box, { marginTop: 1, children: [
35057
+ /* @__PURE__ */ jsx76(Text, { bold: true, children: "Interval: " }),
35058
+ /* @__PURE__ */ jsx76(Text, { color: "yellow", children: shadow.intervalMs >= 1e3 ? `${shadow.intervalMs / 1e3}s` : `${shadow.intervalMs}ms` }),
35059
+ /* @__PURE__ */ jsx76(Text, { dimColor: true, children: " (min 5s)" })
34163
35060
  ] }),
34164
- /* @__PURE__ */ jsx73(Box, { marginTop: 1, children: /* @__PURE__ */ jsx73(Text, { dimColor: true, children: shadow.running ? "Press t to stop the Shadow Agent" : "Press s to start the Shadow Agent" }) })
35061
+ /* @__PURE__ */ jsx76(Box, { marginTop: 1, children: /* @__PURE__ */ jsx76(Text, { dimColor: true, children: shadow.running ? "Press t to stop the Shadow Agent" : "Press s to start the Shadow Agent" }) })
34165
35062
  ] }),
34166
- hint ? /* @__PURE__ */ jsx73(Box, { marginTop: 1, children: /* @__PURE__ */ jsx73(Text, { dimColor: true, children: hint }) }) : null
35063
+ hint ? /* @__PURE__ */ jsx76(Box, { marginTop: 1, children: /* @__PURE__ */ jsx76(Text, { dimColor: true, children: hint }) }) : null
34167
35064
  ] });
34168
35065
  }
34169
35066
 
34170
35067
  // src/components/shell-command-warning.tsx
34171
35068
  import { writeOut as writeOut3 } from "@wrongstack/core/utils";
34172
35069
  import React9 from "react";
34173
- import { jsx as jsx74, jsxs as jsxs72 } from "react/jsx-runtime";
35070
+ import { jsx as jsx77, jsxs as jsxs74 } from "react/jsx-runtime";
34174
35071
  function truncateShellCommandWarningCommand(text, max = 80) {
34175
35072
  return text.length <= max ? text : `${text.slice(0, max - 1)}\u2026`;
34176
35073
  }
@@ -34188,30 +35085,30 @@ function ShellCommandWarning({
34188
35085
  if (ch === "n") onDecision("no");
34189
35086
  if (ch === "d") onDecision("dont-show-again");
34190
35087
  });
34191
- return /* @__PURE__ */ jsxs72(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
34192
- /* @__PURE__ */ jsxs72(Box, { flexDirection: "row", children: [
34193
- /* @__PURE__ */ jsx74(Text, { bold: true, color: "yellow", children: "\u26A0 SHELL COMMAND" }),
34194
- /* @__PURE__ */ jsx74(Text, { children: " " }),
34195
- /* @__PURE__ */ jsxs72(Text, { bold: true, color: "white", children: [
35088
+ return /* @__PURE__ */ jsxs74(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
35089
+ /* @__PURE__ */ jsxs74(Box, { flexDirection: "row", children: [
35090
+ /* @__PURE__ */ jsx77(Text, { bold: true, color: "yellow", children: "\u26A0 SHELL COMMAND" }),
35091
+ /* @__PURE__ */ jsx77(Text, { children: " " }),
35092
+ /* @__PURE__ */ jsxs74(Text, { bold: true, color: "white", children: [
34196
35093
  "!",
34197
35094
  truncateShellCommandWarningCommand(command)
34198
35095
  ] })
34199
35096
  ] }),
34200
- /* @__PURE__ */ jsx74(Text, { dimColor: true, children: "This will execute in your shell via /dev. Only run commands you trust." }),
34201
- /* @__PURE__ */ jsx74(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
34202
- /* @__PURE__ */ jsx74(Box, { flexDirection: "row", children: /* @__PURE__ */ jsxs72(Text, { children: [
34203
- /* @__PURE__ */ jsx74(Text, { bold: true, color: "green", children: "[y]" }),
34204
- /* @__PURE__ */ jsx74(Text, { dimColor: true, children: "es " }),
34205
- /* @__PURE__ */ jsx74(Text, { bold: true, color: "red", children: "[n]" }),
34206
- /* @__PURE__ */ jsx74(Text, { dimColor: true, children: "o " }),
34207
- /* @__PURE__ */ jsx74(Text, { bold: true, color: "cyan", children: "[d]" }),
34208
- /* @__PURE__ */ jsx74(Text, { dimColor: true, children: "ont show again" })
35097
+ /* @__PURE__ */ jsx77(Text, { dimColor: true, children: "This will execute in your shell via /dev. Only run commands you trust." }),
35098
+ /* @__PURE__ */ jsx77(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
35099
+ /* @__PURE__ */ jsx77(Box, { flexDirection: "row", children: /* @__PURE__ */ jsxs74(Text, { children: [
35100
+ /* @__PURE__ */ jsx77(Text, { bold: true, color: "green", children: "[y]" }),
35101
+ /* @__PURE__ */ jsx77(Text, { dimColor: true, children: "es " }),
35102
+ /* @__PURE__ */ jsx77(Text, { bold: true, color: "red", children: "[n]" }),
35103
+ /* @__PURE__ */ jsx77(Text, { dimColor: true, children: "o " }),
35104
+ /* @__PURE__ */ jsx77(Text, { bold: true, color: "cyan", children: "[d]" }),
35105
+ /* @__PURE__ */ jsx77(Text, { dimColor: true, children: "ont show again" })
34209
35106
  ] }) })
34210
35107
  ] });
34211
35108
  }
34212
35109
 
34213
35110
  // src/components/slash-confirm-panel.tsx
34214
- import { jsx as jsx75, jsxs as jsxs73 } from "react/jsx-runtime";
35111
+ import { jsx as jsx78, jsxs as jsxs75 } from "react/jsx-runtime";
34215
35112
  function slashConfirmationDecision(input, key, defaultYes) {
34216
35113
  if (key.escape) return "cancel";
34217
35114
  if (key.return) return defaultYes;
@@ -34225,28 +35122,28 @@ function SlashConfirmPanel({
34225
35122
  question,
34226
35123
  defaultYes
34227
35124
  }) {
34228
- return /* @__PURE__ */ jsxs73(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginY: 1, children: [
34229
- /* @__PURE__ */ jsx75(Text, { bold: true, color: "yellow", children: "? CONFIRM ACTION" }),
34230
- /* @__PURE__ */ jsx75(Box, { marginTop: 1, children: /* @__PURE__ */ jsx75(Text, { children: question }) }),
34231
- /* @__PURE__ */ jsx75(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs73(Text, { children: [
34232
- /* @__PURE__ */ jsx75(Text, { bold: true, color: "green", children: "[y]" }),
35125
+ return /* @__PURE__ */ jsxs75(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginY: 1, children: [
35126
+ /* @__PURE__ */ jsx78(Text, { bold: true, color: "yellow", children: "? CONFIRM ACTION" }),
35127
+ /* @__PURE__ */ jsx78(Box, { marginTop: 1, children: /* @__PURE__ */ jsx78(Text, { children: question }) }),
35128
+ /* @__PURE__ */ jsx78(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs75(Text, { children: [
35129
+ /* @__PURE__ */ jsx78(Text, { bold: true, color: "green", children: "[y]" }),
34233
35130
  "es",
34234
35131
  " ",
34235
- /* @__PURE__ */ jsx75(Text, { bold: true, color: "red", children: "[n]" }),
35132
+ /* @__PURE__ */ jsx78(Text, { bold: true, color: "red", children: "[n]" }),
34236
35133
  "o",
34237
35134
  " ",
34238
- /* @__PURE__ */ jsx75(Text, { bold: true, children: "Enter" }),
35135
+ /* @__PURE__ */ jsx78(Text, { bold: true, children: "Enter" }),
34239
35136
  " = ",
34240
35137
  defaultYes ? "yes" : "no",
34241
35138
  " ",
34242
- /* @__PURE__ */ jsx75(Text, { bold: true, children: "Esc/q" }),
35139
+ /* @__PURE__ */ jsx78(Text, { bold: true, children: "Esc/q" }),
34243
35140
  " = cancel"
34244
35141
  ] }) })
34245
35142
  ] });
34246
35143
  }
34247
35144
 
34248
35145
  // src/components/slash-menu.tsx
34249
- import { jsx as jsx76, jsxs as jsxs74 } from "react/jsx-runtime";
35146
+ import { jsx as jsx79, jsxs as jsxs76 } from "react/jsx-runtime";
34250
35147
  var MAX_VISIBLE_ITEMS = 8;
34251
35148
  function SlashMenu({ query, matches, selected }) {
34252
35149
  const placeholder2 = query ? `/${query}` : "/";
@@ -34265,59 +35162,59 @@ function SlashMenu({ query, matches, selected }) {
34265
35162
  const visible = windowRows2(rows, selectedRowIdx < 0 ? 0 : selectedRowIdx, MAX_VISIBLE_ITEMS);
34266
35163
  const hiddenAbove = visible.start;
34267
35164
  const hiddenBelow = rows.length - visible.end;
34268
- return /* @__PURE__ */ jsxs74(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
34269
- /* @__PURE__ */ jsxs74(Text, { bold: true, color: "cyan", children: [
35165
+ return /* @__PURE__ */ jsxs76(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
35166
+ /* @__PURE__ */ jsxs76(Text, { bold: true, color: "cyan", children: [
34270
35167
  "\u2501\u2501 Command palette \u2501\u2501 ",
34271
- /* @__PURE__ */ jsx76(Text, { dimColor: true, children: placeholder2 }),
35168
+ /* @__PURE__ */ jsx79(Text, { dimColor: true, children: placeholder2 }),
34272
35169
  " ",
34273
- /* @__PURE__ */ jsxs74(Text, { dimColor: true, children: [
35170
+ /* @__PURE__ */ jsxs76(Text, { dimColor: true, children: [
34274
35171
  "(",
34275
35172
  resultMeta,
34276
35173
  ")"
34277
35174
  ] })
34278
35175
  ] }),
34279
- /* @__PURE__ */ jsx76(Text, { dimColor: true, children: "Type to filter commands by name, alias, or description." }),
34280
- hiddenAbove > 0 && /* @__PURE__ */ jsxs74(Text, { dimColor: true, children: [
35176
+ /* @__PURE__ */ jsx79(Text, { dimColor: true, children: "Type to filter commands by name, alias, or description." }),
35177
+ hiddenAbove > 0 && /* @__PURE__ */ jsxs76(Text, { dimColor: true, children: [
34281
35178
  " \u2191 ",
34282
35179
  hiddenAbove,
34283
35180
  " more"
34284
35181
  ] }),
34285
- visible.contextHeader && /* @__PURE__ */ jsxs74(Text, { bold: true, color: "yellow", dimColor: true, children: [
35182
+ visible.contextHeader && /* @__PURE__ */ jsxs76(Text, { bold: true, color: "yellow", dimColor: true, children: [
34286
35183
  " ",
34287
35184
  visible.contextHeader
34288
35185
  ] }),
34289
35186
  visible.rows.map((row) => {
34290
35187
  if (row.type === "header") {
34291
- return /* @__PURE__ */ jsxs74(Text, { bold: true, color: "yellow", dimColor: true, children: [
35188
+ return /* @__PURE__ */ jsxs76(Text, { bold: true, color: "yellow", dimColor: true, children: [
34292
35189
  " ",
34293
35190
  row.category
34294
35191
  ] }, `cat-${row.category}`);
34295
35192
  }
34296
35193
  const { match: m, index: i } = row;
34297
- return /* @__PURE__ */ jsxs74(Text, { inverse: i === selected, ...i === selected ? { color: "cyan" } : {}, children: [
35194
+ return /* @__PURE__ */ jsxs76(Text, { inverse: i === selected, ...i === selected ? { color: "cyan" } : {}, children: [
34298
35195
  i === selected ? "\u203A " : " ",
34299
- /* @__PURE__ */ jsx76(Text, { bold: true, children: m.name }),
34300
- m.argsHint ? /* @__PURE__ */ jsxs74(Text, { dimColor: true, children: [
35196
+ /* @__PURE__ */ jsx79(Text, { bold: true, children: m.name }),
35197
+ m.argsHint ? /* @__PURE__ */ jsxs76(Text, { dimColor: true, children: [
34301
35198
  " ",
34302
35199
  m.argsHint
34303
35200
  ] }) : null,
34304
- m.matchedAlias ? /* @__PURE__ */ jsxs74(Text, { dimColor: true, children: [
35201
+ m.matchedAlias ? /* @__PURE__ */ jsxs76(Text, { dimColor: true, children: [
34305
35202
  " alias /",
34306
35203
  m.matchedAlias
34307
35204
  ] }) : null,
34308
- /* @__PURE__ */ jsxs74(Text, { dimColor: true, children: [
35205
+ /* @__PURE__ */ jsxs76(Text, { dimColor: true, children: [
34309
35206
  " \u2014 ",
34310
35207
  m.description
34311
35208
  ] })
34312
35209
  ] }, m.name);
34313
35210
  }),
34314
- hiddenBelow > 0 && /* @__PURE__ */ jsxs74(Text, { dimColor: true, children: [
35211
+ hiddenBelow > 0 && /* @__PURE__ */ jsxs76(Text, { dimColor: true, children: [
34315
35212
  " \u2193 ",
34316
35213
  hiddenBelow,
34317
35214
  " more"
34318
35215
  ] }),
34319
- matches.length === 0 && /* @__PURE__ */ jsx76(Text, { dimColor: true, children: "No matching commands" }),
34320
- /* @__PURE__ */ jsx76(Text, { dimColor: true, children: "\u2500\u2500\u2500 \u2191\u2193 nav \xB7 Enter run \xB7 Tab fill \xB7 Esc close" })
35216
+ matches.length === 0 && /* @__PURE__ */ jsx79(Text, { dimColor: true, children: "No matching commands" }),
35217
+ /* @__PURE__ */ jsx79(Text, { dimColor: true, children: "\u2500\u2500\u2500 \u2191\u2193 nav \xB7 Enter run \xB7 Tab fill \xB7 Esc close" })
34321
35218
  ] });
34322
35219
  }
34323
35220
  function windowRows2(rows, focus, max) {
@@ -34348,17 +35245,17 @@ function windowRows2(rows, focus, max) {
34348
35245
  }
34349
35246
 
34350
35247
  // src/components/tools-picker.tsx
34351
- import { Fragment as Fragment26, jsx as jsx77, jsxs as jsxs75 } from "react/jsx-runtime";
35248
+ import { Fragment as Fragment27, jsx as jsx80, jsxs as jsxs77 } from "react/jsx-runtime";
34352
35249
  var CHROME_ROWS6 = 15;
34353
35250
  var MAX_PICKER_ITEMS2 = 15;
34354
35251
  function toolActionLabel(enabled) {
34355
35252
  return enabled ? "Enter makes this tool passive" : "Enter re-enables this tool";
34356
35253
  }
34357
35254
  function statusBadge2(enabled) {
34358
- return enabled ? /* @__PURE__ */ jsx77(Text, { color: "green", children: "\u25CF active" }) : /* @__PURE__ */ jsx77(Text, { color: "red", children: "\u25CB passive" });
35255
+ return enabled ? /* @__PURE__ */ jsx80(Text, { color: "green", children: "\u25CF active" }) : /* @__PURE__ */ jsx80(Text, { color: "red", children: "\u25CB passive" });
34359
35256
  }
34360
35257
  function rwBadge(mutating) {
34361
- return mutating ? /* @__PURE__ */ jsx77(Text, { color: "yellow", children: "mut" }) : /* @__PURE__ */ jsx77(Text, { color: "cyan", children: "ro" });
35258
+ return mutating ? /* @__PURE__ */ jsx80(Text, { color: "yellow", children: "mut" }) : /* @__PURE__ */ jsx80(Text, { color: "cyan", children: "ro" });
34362
35259
  }
34363
35260
  function displayCategory(cat) {
34364
35261
  if (!cat || cat.trim() === "") return "Other";
@@ -34457,19 +35354,19 @@ function ToolsPicker({
34457
35354
  const hiddenAbove = win.start;
34458
35355
  const hiddenBelow = rows.length - win.end;
34459
35356
  const hasFilter = filterActive;
34460
- return /* @__PURE__ */ jsxs75(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1, children: [
34461
- /* @__PURE__ */ jsx77(Text, { bold: true, color: "green", children: "\u2501\u2501 Tools \u2501\u2501" }),
34462
- /* @__PURE__ */ jsx77(Text, { dimColor: true, children: hasFilter ? `Filter: ${filter} (${visibleItems.length} match${visibleItems.length === 1 ? "" : "es"}) \xB7 Backspace edit \xB7 Esc clear` : `\u2191/\u2193 select \xB7 type to filter \xB7 Enter toggles \xB7 Esc close \xB7 ${enabledCount} active / ${passiveCount} passive` }),
34463
- /* @__PURE__ */ jsx77(Text, { dimColor: true, children: "Passive tools stay listed for this session so you can select them and re-enable them later." }),
34464
- /* @__PURE__ */ jsx77(Box, { marginTop: 1, flexDirection: "column", children: total === 0 ? /* @__PURE__ */ jsx77(Text, { dimColor: true, children: busy ? "Loading tools\u2026" : "No tools registered." }) : visibleItems.length === 0 ? /* @__PURE__ */ jsxs75(Text, { dimColor: true, children: [
35357
+ return /* @__PURE__ */ jsxs77(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1, children: [
35358
+ /* @__PURE__ */ jsx80(Text, { bold: true, color: "green", children: "\u2501\u2501 Tools \u2501\u2501" }),
35359
+ /* @__PURE__ */ jsx80(Text, { dimColor: true, children: hasFilter ? `Filter: ${filter} (${visibleItems.length} match${visibleItems.length === 1 ? "" : "es"}) \xB7 Backspace edit \xB7 Esc clear` : `\u2191/\u2193 select \xB7 type to filter \xB7 Enter toggles \xB7 Esc close \xB7 ${enabledCount} active / ${passiveCount} passive` }),
35360
+ /* @__PURE__ */ jsx80(Text, { dimColor: true, children: "Passive tools stay listed for this session so you can select them and re-enable them later." }),
35361
+ /* @__PURE__ */ jsx80(Box, { marginTop: 1, flexDirection: "column", children: total === 0 ? /* @__PURE__ */ jsx80(Text, { dimColor: true, children: busy ? "Loading tools\u2026" : "No tools registered." }) : visibleItems.length === 0 ? /* @__PURE__ */ jsxs77(Text, { dimColor: true, children: [
34465
35362
  'No tools match "',
34466
35363
  filter,
34467
35364
  '".'
34468
- ] }) : /* @__PURE__ */ jsxs75(Fragment26, { children: [
34469
- hiddenAbove > 0 ? /* @__PURE__ */ jsx77(Text, { dimColor: true, children: ` \u2191 ${hiddenAbove} more` }) : null,
35365
+ ] }) : /* @__PURE__ */ jsxs77(Fragment27, { children: [
35366
+ hiddenAbove > 0 ? /* @__PURE__ */ jsx80(Text, { dimColor: true, children: ` \u2191 ${hiddenAbove} more` }) : null,
34470
35367
  displayRows.map(({ item, index }) => {
34471
35368
  const focused = index === visibleSelected;
34472
- return /* @__PURE__ */ jsxs75(
35369
+ return /* @__PURE__ */ jsxs77(
34473
35370
  Text,
34474
35371
  {
34475
35372
  inverse: focused,
@@ -34479,9 +35376,9 @@ function ToolsPicker({
34479
35376
  focused ? "\u203A " : " ",
34480
35377
  statusBadge2(item.enabled),
34481
35378
  " ",
34482
- /* @__PURE__ */ jsx77(Text, { bold: true, children: fitCell(item.name, columnWidths.name) }),
35379
+ /* @__PURE__ */ jsx80(Text, { bold: true, children: fitCell(item.name, columnWidths.name) }),
34483
35380
  " ",
34484
- /* @__PURE__ */ jsxs75(Text, { dimColor: true, children: [
35381
+ /* @__PURE__ */ jsxs77(Text, { dimColor: true, children: [
34485
35382
  fitCell(displayCategory(item.category), columnWidths.category),
34486
35383
  " ",
34487
35384
  fitCell(`[${item.owner}]`, columnWidths.owner),
@@ -34491,7 +35388,7 @@ function ToolsPicker({
34491
35388
  " ",
34492
35389
  fitCell(item.permission, columnWidths.permission),
34493
35390
  " ",
34494
- /* @__PURE__ */ jsxs75(Text, { color: item.descMode === "simple" ? "yellow" : void 0, children: [
35391
+ /* @__PURE__ */ jsxs77(Text, { color: item.descMode === "simple" ? "yellow" : void 0, children: [
34495
35392
  "desc:",
34496
35393
  item.descMode
34497
35394
  ] })
@@ -34501,21 +35398,21 @@ function ToolsPicker({
34501
35398
  item.name
34502
35399
  );
34503
35400
  }),
34504
- hiddenBelow > 0 ? /* @__PURE__ */ jsx77(Text, { dimColor: true, children: ` \u2193 ${hiddenBelow} more` }) : null
35401
+ hiddenBelow > 0 ? /* @__PURE__ */ jsx80(Text, { dimColor: true, children: ` \u2193 ${hiddenBelow} more` }) : null
34505
35402
  ] }) }),
34506
- selectedItem ? /* @__PURE__ */ jsxs75(Box, { marginTop: 1, flexDirection: "column", children: [
34507
- /* @__PURE__ */ jsxs75(Text, { children: [
34508
- /* @__PURE__ */ jsx77(Text, { color: selectedItem.enabled ? "green" : "red", children: toolActionLabel(selectedItem.enabled) }),
34509
- /* @__PURE__ */ jsx77(Text, { dimColor: true, children: ` \xB7 ${selectedItem.mutating ? "Mutating" : "Read-only"} \xB7 permission: ${selectedItem.permission} \xB7 descriptions: ${selectedItem.descMode}` })
35403
+ selectedItem ? /* @__PURE__ */ jsxs77(Box, { marginTop: 1, flexDirection: "column", children: [
35404
+ /* @__PURE__ */ jsxs77(Text, { children: [
35405
+ /* @__PURE__ */ jsx80(Text, { color: selectedItem.enabled ? "green" : "red", children: toolActionLabel(selectedItem.enabled) }),
35406
+ /* @__PURE__ */ jsx80(Text, { dimColor: true, children: ` \xB7 ${selectedItem.mutating ? "Mutating" : "Read-only"} \xB7 permission: ${selectedItem.permission} \xB7 descriptions: ${selectedItem.descMode}` })
34510
35407
  ] }),
34511
- /* @__PURE__ */ jsx77(Text, { dimColor: true, wrap: "truncate-end", children: selectedItem.description || "No description provided." })
35408
+ /* @__PURE__ */ jsx80(Text, { dimColor: true, wrap: "truncate-end", children: selectedItem.description || "No description provided." })
34512
35409
  ] }) : null,
34513
- hint ? /* @__PURE__ */ jsx77(Box, { marginTop: 1, children: /* @__PURE__ */ jsx77(Text, { dimColor: true, children: hint }) }) : null
35410
+ hint ? /* @__PURE__ */ jsx80(Box, { marginTop: 1, children: /* @__PURE__ */ jsx80(Text, { dimColor: true, children: hint }) }) : null
34514
35411
  ] });
34515
35412
  }
34516
35413
 
34517
35414
  // src/app-view.tsx
34518
- import { jsx as jsx78, jsxs as jsxs76 } from "react/jsx-runtime";
35415
+ import { jsx as jsx81, jsxs as jsxs78 } from "react/jsx-runtime";
34519
35416
  var CONTINUE_CONFIRM_DELAY_MS = 4e3;
34520
35417
  var INPUT_PROMPT = DEFAULT_INPUT_PROMPT;
34521
35418
  function AppView({ host, runtime }) {
@@ -34534,6 +35431,7 @@ function AppView({ host, runtime }) {
34534
35431
  dispatch,
34535
35432
  activity,
34536
35433
  environment,
35434
+ statusbar,
34537
35435
  viewState,
34538
35436
  historyScrollRef,
34539
35437
  onScrollInfo,
@@ -34553,11 +35451,17 @@ function AppView({ host, runtime }) {
34553
35451
  refineModel,
34554
35452
  setEnhanceCountdown,
34555
35453
  enhanceDelayMs,
34556
- layoutStore
35454
+ layoutStore,
35455
+ mailbox
34557
35456
  } = runtime;
34558
35457
  const { nowTick, workingTimeMs, enhanceDots } = activity;
34559
- const { setYoloLive, autonomyLive } = environment;
35458
+ const { setYoloLive, autonomyLive, liveModel, liveProvider } = environment;
34560
35459
  const { inputHint, composerStatus, composerAnimationStyle, inputHeight, hideInput } = viewState;
35460
+ const { stdout } = useStdout();
35461
+ const termCols = stdout?.columns ?? 80;
35462
+ const overlayOpen = isPickerOverlayOpen(state) || state.coordinator.monitorOpen || state.auditPanelOpen || state.connectionsPanelOpen || state.helpOpen || state.agentsMonitorOpen || state.monitorOpen || state.contextPanelOpen || state.processListOpen || state.todosMonitorOpen || state.worktreeMonitorOpen || state.planPanelOpen || state.kanbanPanelOpen || state.queuePanelOpen || state.goalPanelOpen || state.goalKanbanPanelOpen || state.cronMonitorOpen || state.rewindOverlay != null || state.shellCommandWarning != null || state.confirmQueue.length > 0 || state.clearConfirm != null || state.exitConfirm != null || state.slashConfirm != null || state.escConfirm != null || state.sendModePicker != null || state.enhance != null || state.enhanceBusy || state.refineCountdown != null || state.refineFailure != null || state.continueConfirm != null || state.brainPrompt != null || mailbox.mailboxPanelOpen || (state.goalRun?.monitorOpen ?? false) || (state.sddBoard?.monitorOpen ?? false);
35463
+ const sidebarWidth = overlayOpen ? 0 : computeSidebarWidth(termCols);
35464
+ const mainColumnWidth = termCols - sidebarWidth;
34561
35465
  return (
34562
35466
  /* Hard viewport cap. The managed layout aims for exactly termRows
34563
35467
  (history vp + measured bottom region), but the bottom region grows a
@@ -34571,516 +35475,538 @@ function AppView({ host, runtime }) {
34571
35475
  the history box (Ink-7: flex-end clips top), so a freshly-opened picker
34572
35476
  or grown input is fully visible immediately while history briefly loses
34573
35477
  its top rows until the viewport re-measures. */
34574
- /* @__PURE__ */ jsx78(
35478
+ /* @__PURE__ */ jsx81(
34575
35479
  Box,
34576
35480
  {
34577
35481
  flexDirection: "column",
34578
35482
  height: runtime.termRows,
34579
35483
  overflowY: "hidden",
34580
35484
  justifyContent: "flex-end",
34581
- children: /* @__PURE__ */ jsxs76(Box, { flexDirection: "column", flexShrink: 0, children: [
34582
- /* @__PURE__ */ jsx78(
34583
- ScrollableHistory,
34584
- {
34585
- entries: state.entries,
34586
- toolStream: state.toolStream,
34587
- viewportRows: state.viewportRows,
34588
- controllerRef: historyScrollRef,
34589
- onScrollInfo,
34590
- setSuggestions,
34591
- autonomyMode: autonomyLive,
34592
- multiDiffSummaryThreshold: state.settingsPicker.multiDiffSummaryThreshold,
34593
- todos: liveTodos,
34594
- showModelReasoning: state.settingsPicker.open ? state.settingsPicker.showModelReasoning : liveSettings?.showModelReasoning ?? true,
34595
- showSageMemoryInject: state.settingsPicker.open ? state.settingsPicker.showSageMemoryInject : liveSettings?.showSageMemoryInject ?? false,
34596
- layoutStore,
34597
- copiedEntryId: state.copiedEntryId,
34598
- onRequestOlderEntries: runtime.onRequestOlderEntries
34599
- },
34600
- `history-gen-${state.historyGen}`
34601
- ),
34602
- /* @__PURE__ */ jsxs76(Box, { flexDirection: "column", flexShrink: 0, ref: bottomRegionRef, children: [
34603
- /* @__PURE__ */ jsx78(
34604
- Input,
34605
- {
34606
- prompt: INPUT_PROMPT,
34607
- value: state.buffer,
34608
- cursor: state.cursor,
34609
- title: `WRONGSTACK${appVersion ? ` v${appVersion}` : ""}`,
34610
- status: composerStatus,
34611
- animationStyle: composerAnimationStyle,
34612
- hidden: hideInput,
34613
- placeholderHeight: inputHeight,
34614
- disabled: state.status === "aborting" && !state.steeringPending || state.confirmQueue.length > 0,
34615
- hint: inputHint,
34616
- onKey: stableOnKey,
34617
- workingTime: workingTimeMs
34618
- }
34619
- ),
34620
- state.picker.open ? /* @__PURE__ */ jsx78(
34621
- FilePicker,
34622
- {
34623
- query: state.picker.query,
34624
- matches: state.picker.matches,
34625
- selected: state.picker.selected
34626
- }
34627
- ) : null,
34628
- state.slashPicker.open ? /* @__PURE__ */ jsx78(
34629
- SlashMenu,
34630
- {
34631
- query: state.slashPicker.query,
34632
- matches: state.slashPicker.matches,
34633
- selected: state.slashPicker.selected
34634
- }
34635
- ) : null,
34636
- state.modelPicker.open ? /* @__PURE__ */ jsx78(
34637
- ModelPicker,
34638
- {
34639
- step: state.modelPicker.step,
34640
- providerOptions: state.modelPicker.providerOptions,
34641
- modelOptions: state.modelPicker.modelOptions,
34642
- filteredOptions: state.modelPicker.filteredOptions,
34643
- selected: state.modelPicker.selected,
34644
- pickedProviderId: state.modelPicker.pickedProviderId,
34645
- searchQuery: state.modelPicker.searchQuery,
34646
- hint: state.modelPicker.hint,
34647
- titleLabel: state.modelPicker.title
34648
- }
34649
- ) : null,
34650
- state.autonomyPicker.open ? /* @__PURE__ */ jsx78(
34651
- AutonomyPicker,
34652
- {
34653
- options: state.autonomyPicker.options,
34654
- selected: state.autonomyPicker.selected,
34655
- hint: state.autonomyPicker.hint
34656
- }
34657
- ) : null,
34658
- state.modePicker.open ? /* @__PURE__ */ jsx78(
34659
- ModePicker,
35485
+ children: /* @__PURE__ */ jsxs78(Box, { flexDirection: "row", width: termCols, flexShrink: 0, overflowX: "hidden", children: [
35486
+ /* @__PURE__ */ jsxs78(Box, { flexDirection: "column", flexShrink: 0, width: mainColumnWidth, overflowX: "hidden", children: [
35487
+ /* @__PURE__ */ jsx81(
35488
+ ScrollableHistory,
34660
35489
  {
34661
- modes: state.modePicker.modes,
34662
- selected: state.modePicker.selected,
34663
- hint: state.modePicker.hint
34664
- }
34665
- ) : null,
34666
- state.designPicker.open ? /* @__PURE__ */ jsx78(
34667
- DesignPicker,
34668
- {
34669
- kits: state.designPicker.kits,
34670
- selected: state.designPicker.selected,
34671
- stack: state.designPicker.stack
34672
- }
34673
- ) : null,
34674
- state.promptPicker.open ? /* @__PURE__ */ jsx78(
34675
- PromptPicker,
34676
- {
34677
- entries: filterPromptPicker(
34678
- state.promptPicker.all,
34679
- state.promptPicker.categories,
34680
- state.promptPicker.catIndex,
34681
- state.promptPicker.recentSlugs
34682
- ),
34683
- selected: state.promptPicker.selected,
34684
- category: state.promptPicker.categories[state.promptPicker.catIndex] ?? "all",
34685
- total: state.promptPicker.all.length
34686
- }
34687
- ) : null,
34688
- state.resumePicker.open ? /* @__PURE__ */ jsx78(
34689
- ResumePicker,
34690
- {
34691
- sessions: state.resumePicker.sessions,
34692
- selected: state.resumePicker.selected,
34693
- busy: state.resumePicker.busy,
34694
- error: state.resumePicker.error,
34695
- hint: state.resumePicker.hint
34696
- }
34697
- ) : null,
34698
- state.settingsPicker.open ? /* @__PURE__ */ jsx78(
34699
- SettingsPicker,
34700
- {
34701
- field: state.settingsPicker.field,
34702
- mode: state.settingsPicker.mode,
34703
- delayMs: state.settingsPicker.delayMs,
34704
- titleAnimation: state.settingsPicker.titleAnimation,
34705
- yolo: state.settingsPicker.yolo,
34706
- fleetChat: state.settingsPicker.fleetChat,
34707
- chime: state.settingsPicker.chime,
34708
- confirmExit: state.settingsPicker.confirmExit,
34709
- nextPrediction: state.settingsPicker.nextPrediction,
34710
- featureMcp: state.settingsPicker.featureMcp,
34711
- featurePlugins: state.settingsPicker.featurePlugins,
34712
- featureMemory: state.settingsPicker.featureMemory,
34713
- featureSkills: state.settingsPicker.featureSkills,
34714
- featureModelsRegistry: state.settingsPicker.featureModelsRegistry,
34715
- tokenSavingTier: state.settingsPicker.tokenSavingTier,
34716
- allowOutsideProjectRoot: state.settingsPicker.allowOutsideProjectRoot,
34717
- contextAutoCompact: state.settingsPicker.contextAutoCompact,
34718
- contextStrategy: state.settingsPicker.contextStrategy,
34719
- contextMode: state.settingsPicker.contextMode,
34720
- maxConcurrent: state.settingsPicker.maxConcurrent,
34721
- logLevel: state.settingsPicker.logLevel,
34722
- auditLevel: state.settingsPicker.auditLevel,
34723
- indexOnStart: state.settingsPicker.indexOnStart,
35490
+ entries: state.entries,
35491
+ toolStream: state.toolStream,
35492
+ viewportRows: state.viewportRows,
35493
+ maxWidth: mainColumnWidth,
35494
+ controllerRef: historyScrollRef,
35495
+ onScrollInfo,
35496
+ setSuggestions,
35497
+ autonomyMode: autonomyLive,
34724
35498
  multiDiffSummaryThreshold: state.settingsPicker.multiDiffSummaryThreshold,
34725
- thinkingWord: state.settingsPicker.thinkingWord,
34726
- thinkingWordEditing: state.settingsPicker.thinkingWordEditing,
34727
- thinkingWordDraft: state.settingsPicker.thinkingWordDraft,
34728
- maxIterations: state.settingsPicker.maxIterations,
34729
- autoProceedMaxIterations: state.settingsPicker.autoProceedMaxIterations,
34730
- enhanceDelayMs: state.settingsPicker.enhanceDelayMs,
34731
- preRefineSeconds: state.settingsPicker.preRefineSeconds,
34732
- enhanceEnabled: state.settingsPicker.enhanceEnabled,
34733
- enhanceLanguage: state.settingsPicker.enhanceLanguage,
34734
- debugStream: state.settingsPicker.debugStream,
34735
- statuslineMode: state.settingsPicker.statuslineMode,
34736
- reasoningMode: state.settingsPicker.reasoningMode,
34737
- reasoningEffort: state.settingsPicker.reasoningEffort,
34738
- reasoningPreserve: state.settingsPicker.reasoningPreserve,
34739
- cacheTtl: state.settingsPicker.cacheTtl,
34740
- configScope: state.settingsPicker.configScope,
34741
- profileConfigPath,
34742
- animationStyle: state.settingsPicker.animationStyle,
34743
- breakerEnabled: state.settingsPicker.breakerEnabled,
34744
- breakerAutoKillResetMs: state.settingsPicker.breakerAutoKillResetMs,
34745
- showModelReasoning: state.settingsPicker.showModelReasoning,
34746
- showAgentSwarmPanel: state.settingsPicker.showAgentSwarmPanel,
34747
- showSageMemoryInject: state.settingsPicker.showSageMemoryInject,
34748
- sageMemoryInjectThreshold: state.settingsPicker.sageMemoryInjectThreshold,
34749
- readSymbols: state.settingsPicker.readSymbols,
34750
- filter: state.settingsPicker.filter,
34751
- hint: state.settingsPicker.hint
34752
- }
34753
- ) : null,
34754
- state.statuslinePicker.open ? /* @__PURE__ */ jsx78(
34755
- StatuslinePicker,
34756
- {
34757
- field: state.statuslinePicker.field,
34758
- hiddenItems: state.statuslinePicker.hiddenItems,
34759
- visibleChips: state.statuslinePicker.visibleChips,
34760
- hint: state.statuslinePicker.hint
34761
- }
34762
- ) : null,
34763
- state.pluginPicker.open ? /* @__PURE__ */ jsx78(
34764
- PluginPicker,
34765
- {
34766
- items: state.pluginPicker.items,
34767
- selected: state.pluginPicker.selected,
34768
- busy: state.pluginPicker.busy,
34769
- hint: state.pluginPicker.hint
34770
- }
34771
- ) : null,
34772
- state.mcpPicker.open ? /* @__PURE__ */ jsx78(
34773
- McpPicker,
34774
- {
34775
- items: state.mcpPicker.items,
34776
- selected: state.mcpPicker.selected,
34777
- busy: state.mcpPicker.busy,
34778
- hint: state.mcpPicker.hint
34779
- }
34780
- ) : null,
34781
- state.toolsPicker.open ? /* @__PURE__ */ jsx78(
34782
- ToolsPicker,
34783
- {
34784
- items: state.toolsPicker.items,
34785
- selected: state.toolsPicker.selected,
34786
- busy: state.toolsPicker.busy,
34787
- hint: state.toolsPicker.hint,
34788
- filter: state.toolsPicker.filter
34789
- }
34790
- ) : null,
34791
- state.brainPanel.open && !state.modelPicker.open ? /* @__PURE__ */ jsx78(BrainPanel, { ...state.brainPanel }) : null,
34792
- state.helpPanel.open ? /* @__PURE__ */ jsx78(
34793
- HelpPanel,
34794
- {
34795
- entries: state.helpPanel.entries,
34796
- filter: state.helpPanel.filter,
34797
- selected: state.helpPanel.selected,
34798
- hint: state.helpPanel.hint
34799
- }
34800
- ) : null,
34801
- state.shadowPanel.open ? /* @__PURE__ */ jsx78(ShadowPanel, { shadow: state.shadowPanel.shadow, hint: state.shadowPanel.hint }) : null,
34802
- state.authPanel.open ? /* @__PURE__ */ jsx78(AuthPanel, { panel: state.authPanel }) : null,
34803
- state.projectPicker.open ? /* @__PURE__ */ jsx78(
34804
- ProjectPicker,
34805
- {
34806
- items: state.projectPicker.items,
34807
- selected: state.projectPicker.selected,
34808
- filter: state.projectPicker.filter,
34809
- hint: state.projectPicker.hint
34810
- }
34811
- ) : null,
34812
- state.fKeyPicker.open ? /* @__PURE__ */ jsx78(FKeyPicker, { selected: state.fKeyPicker.selected }) : null,
34813
- state.coordinator.monitorOpen ? /* @__PURE__ */ jsx78(
34814
- CoordinatorPanel,
34815
- {
34816
- coordinator: state.coordinator,
34817
- nowTick,
34818
- onClose: () => dispatch({ type: "toggleCoordinatorMonitor" })
34819
- }
34820
- ) : null,
34821
- state.auditPanelOpen ? /* @__PURE__ */ jsx78(
34822
- AuditPanel,
34823
- {
34824
- sideEffects: agent.ctx.sideEffects ?? [],
34825
- onClose: () => dispatch({ type: "toggleAuditPanel" })
34826
- }
34827
- ) : null,
34828
- state.connectionsPanelOpen ? /* @__PURE__ */ jsx78(
34829
- ConnectionsPanel,
34830
- {
34831
- projectRoot: agent.ctx.projectRoot,
34832
- onClose: () => dispatch({ type: "toggleConnectionsPanel" })
34833
- }
34834
- ) : null,
34835
- state.rewindOverlay ? (() => {
34836
- const overlay = state.rewindOverlay;
34837
- return /* @__PURE__ */ jsx78(
34838
- CheckpointTimeline,
35499
+ todos: liveTodos,
35500
+ showModelReasoning: state.settingsPicker.open ? state.settingsPicker.showModelReasoning : liveSettings?.showModelReasoning ?? true,
35501
+ showSageMemoryInject: state.settingsPicker.open ? state.settingsPicker.showSageMemoryInject : liveSettings?.showSageMemoryInject ?? false,
35502
+ layoutStore,
35503
+ copiedEntryId: state.copiedEntryId,
35504
+ onRequestOlderEntries: runtime.onRequestOlderEntries
35505
+ },
35506
+ `history-gen-${state.historyGen}`
35507
+ ),
35508
+ /* @__PURE__ */ jsxs78(Box, { flexDirection: "column", flexShrink: 0, ref: bottomRegionRef, width: mainColumnWidth, children: [
35509
+ /* @__PURE__ */ jsx81(
35510
+ Input,
34839
35511
  {
34840
- checkpoints: overlay.checkpoints,
34841
- selected: overlay.selected,
34842
- onSelect: (i) => dispatch({ type: "rewindOverlayMove", delta: i - overlay.selected }),
34843
- onConfirm: (i) => {
34844
- const checkpoint = overlay.checkpoints[i];
34845
- if (checkpoint) handleRewindTo(checkpoint.promptIndex);
34846
- },
34847
- onClose: () => dispatch({ type: "rewindOverlayClose" })
35512
+ prompt: INPUT_PROMPT,
35513
+ value: state.buffer,
35514
+ cursor: state.cursor,
35515
+ title: `WRONGSTACK${appVersion ? ` v${appVersion}` : ""}`,
35516
+ status: composerStatus,
35517
+ animationStyle: composerAnimationStyle,
35518
+ hidden: hideInput,
35519
+ placeholderHeight: inputHeight,
35520
+ maxWidth: mainColumnWidth,
35521
+ disabled: state.status === "aborting" && !state.steeringPending || state.confirmQueue.length > 0,
35522
+ hint: inputHint,
35523
+ onKey: stableOnKey,
35524
+ workingTime: workingTimeMs
34848
35525
  }
34849
- );
34850
- })() : null,
34851
- state.brainPrompt ? /* @__PURE__ */ jsx78(Box, { flexDirection: "column", marginY: 1, flexShrink: 0, children: /* @__PURE__ */ jsx78(
34852
- BrainDecisionPrompt,
34853
- {
34854
- ...state.brainPrompt,
34855
- onAnswer: (answer) => {
34856
- events.emit("brain.human_answered", { ...answer, at: Date.now() });
34857
- dispatch({ type: "brainPromptClear" });
35526
+ ),
35527
+ state.picker.open ? /* @__PURE__ */ jsx81(
35528
+ FilePicker,
35529
+ {
35530
+ query: state.picker.query,
35531
+ matches: state.picker.matches,
35532
+ selected: state.picker.selected
34858
35533
  }
34859
- }
34860
- ) }) : null,
34861
- state.shellCommandWarning ? (() => {
34862
- const info = state.shellCommandWarning;
34863
- let resolved = false;
34864
- const onDecision = (decision) => {
34865
- if (resolved) return;
34866
- resolved = true;
34867
- info.resolve(decision);
34868
- dispatch({ type: "shellCommandWarningClose" });
34869
- };
34870
- return /* @__PURE__ */ jsx78(ShellCommandWarning, { command: info.command, onDecision });
34871
- })() : null,
34872
- state.confirmQueue.length > 0 && (() => {
34873
- const head = expectDefined5(state.confirmQueue[0]);
34874
- let resolved = false;
34875
- const onDecision = (decision) => {
34876
- if (resolved) return;
34877
- resolved = true;
34878
- head.resolve(decision);
34879
- dispatch({ type: "confirmClose" });
34880
- };
34881
- const onEnableYolo = () => {
34882
- if (resolved) return;
34883
- onYolo?.(true);
34884
- setYoloLive(true);
34885
- const cur = getSettings?.();
34886
- if (cur && saveSettings) {
34887
- Promise.resolve(saveSettings({ ...cur, yolo: true })).catch(() => {
34888
- });
35534
+ ) : null,
35535
+ state.slashPicker.open ? /* @__PURE__ */ jsx81(
35536
+ SlashMenu,
35537
+ {
35538
+ query: state.slashPicker.query,
35539
+ matches: state.slashPicker.matches,
35540
+ selected: state.slashPicker.selected
34889
35541
  }
34890
- resolved = true;
34891
- head.resolve("yes");
34892
- dispatch({ type: "confirmClose" });
34893
- };
34894
- return /* @__PURE__ */ jsx78(
34895
- ConfirmPrompt,
35542
+ ) : null,
35543
+ state.modelPicker.open ? /* @__PURE__ */ jsx81(
35544
+ ModelPicker,
34896
35545
  {
34897
- toolName: head.toolName,
34898
- input: head.input,
34899
- suggestedPattern: head.suggestedPattern,
34900
- onDecision,
34901
- onEnableYolo,
34902
- destructive: head.destructive,
34903
- boundaryReason: head.boundaryReason
35546
+ step: state.modelPicker.step,
35547
+ providerOptions: state.modelPicker.providerOptions,
35548
+ modelOptions: state.modelPicker.modelOptions,
35549
+ filteredOptions: state.modelPicker.filteredOptions,
35550
+ selected: state.modelPicker.selected,
35551
+ pickedProviderId: state.modelPicker.pickedProviderId,
35552
+ searchQuery: state.modelPicker.searchQuery,
35553
+ hint: state.modelPicker.hint,
35554
+ titleLabel: state.modelPicker.title
34904
35555
  }
34905
- );
34906
- })(),
34907
- state.clearConfirm ? /* @__PURE__ */ jsx78(
34908
- ClearConfirmPanel,
34909
- {
34910
- leaderActive: state.clearConfirm.leaderActive,
34911
- subagentCount: state.clearConfirm.subagentCount,
34912
- value: state.clearConfirm.value
34913
- }
34914
- ) : null,
34915
- state.exitConfirm ? /* @__PURE__ */ jsx78(
34916
- ExitConfirmPanel,
34917
- {
34918
- leaderActive: state.exitConfirm.leaderActive,
34919
- subagentCount: state.exitConfirm.subagentCount,
34920
- backgroundCount: state.exitConfirm.backgroundCount
34921
- }
34922
- ) : null,
34923
- state.slashConfirm ? /* @__PURE__ */ jsx78(
34924
- SlashConfirmPanel,
34925
- {
34926
- question: state.slashConfirm.question,
34927
- defaultYes: state.slashConfirm.defaultYes
34928
- }
34929
- ) : null,
34930
- state.escConfirm ? /* @__PURE__ */ jsx78(Box, { flexDirection: "column", marginY: 1, flexShrink: 0, children: /* @__PURE__ */ jsx78(
34931
- EscConfirmPrompt,
34932
- {
34933
- runningTools: state.escConfirm.snapshot.runningTools,
34934
- subagentCount: state.escConfirm.snapshot.subagentsTerminated,
34935
- onConfirm: () => {
34936
- const escConfirm = state.escConfirm;
34937
- if (!escConfirm) return;
34938
- const { snapshot } = escConfirm;
34939
- activeCtrlRef.current?.abort("user interrupt (Esc)");
34940
- clearPendingConfirms();
34941
- dispatch({ type: "status", status: "aborting" });
34942
- dispatch({ type: "steerStart", snapshot });
34943
- const escConfirmDir = liveDirector();
34944
- if (escConfirmDir && snapshot.subagentsTerminated > 0) {
34945
- const cap = new Promise((resolve) => {
34946
- const t = setTimeout(resolve, 1500);
34947
- t.unref?.();
34948
- });
34949
- void Promise.race([escConfirmDir.terminateAll().catch(() => void 0), cap]);
34950
- }
34951
- const droppedCount = state.queue.length;
34952
- if (droppedCount > 0) dispatch({ type: "queueClear" });
34953
- const droppedTag = droppedCount > 0 ? ` \xB7 dropped ${droppedCount} queued` : "";
34954
- const fleetTag = snapshot.subagentsTerminated > 0 ? ` \xB7 stopped ${snapshot.subagentsTerminated} subagent${snapshot.subagentsTerminated === 1 ? "" : "s"}` : "";
34955
- dispatch({
34956
- type: "addEntry",
34957
- entry: {
34958
- kind: "warn",
34959
- text: `\u21AF Interrupted${droppedTag}${fleetTag}. Type your new direction.`
34960
- }
34961
- });
34962
- dispatch({ type: "escConfirmClose" });
34963
- },
34964
- onCancel: () => {
34965
- dismissedEscAtRef.current = Date.now();
34966
- dispatch({ type: "escConfirmClose" });
35556
+ ) : null,
35557
+ state.autonomyPicker.open ? /* @__PURE__ */ jsx81(
35558
+ AutonomyPicker,
35559
+ {
35560
+ options: state.autonomyPicker.options,
35561
+ selected: state.autonomyPicker.selected,
35562
+ hint: state.autonomyPicker.hint
34967
35563
  }
34968
- }
34969
- ) }) : null,
34970
- state.sendModePicker ? (() => {
34971
- const info = state.sendModePicker;
34972
- let resolved = false;
34973
- const finish = (decision) => {
34974
- if (resolved) return;
34975
- resolved = true;
34976
- info.resolve(decision);
34977
- };
34978
- return /* @__PURE__ */ jsx78(
34979
- SendModePicker,
35564
+ ) : null,
35565
+ state.modePicker.open ? /* @__PURE__ */ jsx81(
35566
+ ModePicker,
34980
35567
  {
34981
- selected: info.selected,
34982
- messagePreview: info.displayText,
34983
- onMove: (delta) => dispatch({ type: "sendModePickerMove", delta }),
34984
- onSelect: finish
35568
+ modes: state.modePicker.modes,
35569
+ selected: state.modePicker.selected,
35570
+ hint: state.modePicker.hint
34985
35571
  }
34986
- );
34987
- })() : null,
34988
- state.refineCountdown ? (() => {
34989
- const info = state.refineCountdown;
34990
- let resolved = false;
34991
- const onDecision = (decision) => {
34992
- if (resolved) return;
34993
- resolved = true;
34994
- info.resolve(decision);
34995
- };
34996
- return /* @__PURE__ */ jsx78(
34997
- RefineCountdownPanel,
35572
+ ) : null,
35573
+ state.designPicker.open ? /* @__PURE__ */ jsx81(
35574
+ DesignPicker,
34998
35575
  {
34999
- original: info.original,
35000
- seconds: info.seconds,
35001
- onDecision,
35002
- providerId: refineProviderId ?? agent.ctx.provider?.id,
35003
- model: refineModel ?? agent.ctx.model
35576
+ kits: state.designPicker.kits,
35577
+ selected: state.designPicker.selected,
35578
+ stack: state.designPicker.stack
35004
35579
  }
35005
- );
35006
- })() : null,
35007
- state.enhanceBusy && !state.enhance ? /* @__PURE__ */ jsx78(
35008
- RefiningPanel,
35009
- {
35010
- original: enhanceOriginalRef.current,
35011
- elapsedMs: enhanceStartedAt === null ? 0 : Math.max(0, Date.now() - enhanceStartedAt),
35012
- pulseFrame: enhanceDots,
35013
- providerId: refineProviderId ?? agent.ctx.provider?.id,
35014
- model: refineModel ?? agent.ctx.model
35015
- }
35016
- ) : null,
35017
- state.enhance ? (() => {
35018
- const info = state.enhance;
35019
- let resolved = false;
35020
- const onDecision = (decision) => {
35021
- if (resolved) return;
35022
- resolved = true;
35023
- setEnhanceCountdown(null);
35024
- info.resolve(decision);
35025
- };
35026
- return /* @__PURE__ */ jsx78(
35027
- EnhancePanel,
35580
+ ) : null,
35581
+ state.promptPicker.open ? /* @__PURE__ */ jsx81(
35582
+ PromptPicker,
35028
35583
  {
35029
- original: info.original,
35030
- refined: info.refined,
35031
- english: info.english,
35032
- durationMs: enhanceDurationMs ?? 0,
35033
- delayMs: enhanceDelayMs,
35584
+ entries: filterPromptPicker(
35585
+ state.promptPicker.all,
35586
+ state.promptPicker.categories,
35587
+ state.promptPicker.catIndex,
35588
+ state.promptPicker.recentSlugs
35589
+ ),
35590
+ selected: state.promptPicker.selected,
35591
+ category: state.promptPicker.categories[state.promptPicker.catIndex] ?? "all",
35592
+ total: state.promptPicker.all.length
35593
+ }
35594
+ ) : null,
35595
+ state.resumePicker.open ? /* @__PURE__ */ jsx81(
35596
+ ResumePicker,
35597
+ {
35598
+ sessions: state.resumePicker.sessions,
35599
+ selected: state.resumePicker.selected,
35600
+ busy: state.resumePicker.busy,
35601
+ error: state.resumePicker.error,
35602
+ hint: state.resumePicker.hint
35603
+ }
35604
+ ) : null,
35605
+ state.settingsPicker.open ? /* @__PURE__ */ jsx81(
35606
+ SettingsPicker,
35607
+ {
35608
+ field: state.settingsPicker.field,
35609
+ mode: state.settingsPicker.mode,
35610
+ delayMs: state.settingsPicker.delayMs,
35611
+ titleAnimation: state.settingsPicker.titleAnimation,
35612
+ yolo: state.settingsPicker.yolo,
35613
+ fleetChat: state.settingsPicker.fleetChat,
35614
+ chime: state.settingsPicker.chime,
35615
+ confirmExit: state.settingsPicker.confirmExit,
35616
+ nextPrediction: state.settingsPicker.nextPrediction,
35617
+ featureMcp: state.settingsPicker.featureMcp,
35618
+ featurePlugins: state.settingsPicker.featurePlugins,
35619
+ featureMemory: state.settingsPicker.featureMemory,
35620
+ featureSkills: state.settingsPicker.featureSkills,
35621
+ featureModelsRegistry: state.settingsPicker.featureModelsRegistry,
35622
+ tokenSavingTier: state.settingsPicker.tokenSavingTier,
35623
+ allowOutsideProjectRoot: state.settingsPicker.allowOutsideProjectRoot,
35624
+ contextAutoCompact: state.settingsPicker.contextAutoCompact,
35625
+ contextStrategy: state.settingsPicker.contextStrategy,
35626
+ contextMode: state.settingsPicker.contextMode,
35627
+ maxConcurrent: state.settingsPicker.maxConcurrent,
35628
+ logLevel: state.settingsPicker.logLevel,
35629
+ auditLevel: state.settingsPicker.auditLevel,
35630
+ indexOnStart: state.settingsPicker.indexOnStart,
35631
+ multiDiffSummaryThreshold: state.settingsPicker.multiDiffSummaryThreshold,
35632
+ thinkingWord: state.settingsPicker.thinkingWord,
35633
+ thinkingWordEditing: state.settingsPicker.thinkingWordEditing,
35634
+ thinkingWordDraft: state.settingsPicker.thinkingWordDraft,
35635
+ maxIterations: state.settingsPicker.maxIterations,
35636
+ autoProceedMaxIterations: state.settingsPicker.autoProceedMaxIterations,
35637
+ enhanceDelayMs: state.settingsPicker.enhanceDelayMs,
35638
+ preRefineSeconds: state.settingsPicker.preRefineSeconds,
35639
+ enhanceEnabled: state.settingsPicker.enhanceEnabled,
35034
35640
  enhanceLanguage: state.settingsPicker.enhanceLanguage,
35035
- onDecision,
35036
- onTick: (r) => setEnhanceCountdown(r > 0 ? r : null),
35037
- providerId: refineProviderId ?? agent.ctx.provider?.id,
35038
- model: refineModel ?? agent.ctx.model
35641
+ debugStream: state.settingsPicker.debugStream,
35642
+ statuslineMode: state.settingsPicker.statuslineMode,
35643
+ reasoningMode: state.settingsPicker.reasoningMode,
35644
+ reasoningEffort: state.settingsPicker.reasoningEffort,
35645
+ reasoningPreserve: state.settingsPicker.reasoningPreserve,
35646
+ cacheTtl: state.settingsPicker.cacheTtl,
35647
+ configScope: state.settingsPicker.configScope,
35648
+ profileConfigPath,
35649
+ animationStyle: state.settingsPicker.animationStyle,
35650
+ breakerEnabled: state.settingsPicker.breakerEnabled,
35651
+ breakerAutoKillResetMs: state.settingsPicker.breakerAutoKillResetMs,
35652
+ showModelReasoning: state.settingsPicker.showModelReasoning,
35653
+ showAgentSwarmPanel: state.settingsPicker.showAgentSwarmPanel,
35654
+ showSageMemoryInject: state.settingsPicker.showSageMemoryInject,
35655
+ sageMemoryInjectThreshold: state.settingsPicker.sageMemoryInjectThreshold,
35656
+ readSymbols: state.settingsPicker.readSymbols,
35657
+ filter: state.settingsPicker.filter,
35658
+ hint: state.settingsPicker.hint
35039
35659
  }
35040
- );
35041
- })() : null,
35042
- state.refineFailure ? (() => {
35043
- const info = state.refineFailure;
35044
- let resolved = false;
35045
- const onDecision = (decision) => {
35046
- if (resolved) return;
35047
- resolved = true;
35048
- info.resolve(decision);
35049
- };
35050
- return /* @__PURE__ */ jsx78(
35051
- RefineFailurePanel,
35660
+ ) : null,
35661
+ state.statuslinePicker.open ? /* @__PURE__ */ jsx81(
35662
+ StatuslinePicker,
35052
35663
  {
35053
- original: info.original,
35054
- error: info.error,
35055
- elapsedMs: info.elapsedMs,
35056
- fallbackRef: info.fallbackRef,
35057
- models: info.models,
35058
- onDecision
35664
+ field: state.statuslinePicker.field,
35665
+ hiddenItems: state.statuslinePicker.hiddenItems,
35666
+ visibleChips: state.statuslinePicker.visibleChips,
35667
+ hint: state.statuslinePicker.hint
35059
35668
  }
35060
- );
35061
- })() : null,
35062
- state.continueConfirm ? (() => {
35063
- const info = state.continueConfirm;
35064
- let resolved = false;
35065
- const onDecision = (decision) => {
35066
- if (resolved) return;
35067
- resolved = true;
35068
- info.resolve(decision);
35069
- };
35070
- return /* @__PURE__ */ jsx78(
35071
- ContinueConfirmPanel,
35669
+ ) : null,
35670
+ state.pluginPicker.open ? /* @__PURE__ */ jsx81(
35671
+ PluginPicker,
35072
35672
  {
35073
- label: info.label,
35074
- instruction: info.instruction,
35075
- source: info.source,
35076
- grounded: info.grounded,
35077
- delayMs: CONTINUE_CONFIRM_DELAY_MS,
35078
- onDecision
35673
+ items: state.pluginPicker.items,
35674
+ selected: state.pluginPicker.selected,
35675
+ busy: state.pluginPicker.busy,
35676
+ hint: state.pluginPicker.hint
35079
35677
  }
35080
- );
35081
- })() : null,
35082
- /* @__PURE__ */ jsx78(AppStatusRegion, { host, runtime })
35083
- ] })
35678
+ ) : null,
35679
+ state.mcpPicker.open ? /* @__PURE__ */ jsx81(
35680
+ McpPicker,
35681
+ {
35682
+ items: state.mcpPicker.items,
35683
+ selected: state.mcpPicker.selected,
35684
+ busy: state.mcpPicker.busy,
35685
+ hint: state.mcpPicker.hint
35686
+ }
35687
+ ) : null,
35688
+ state.toolsPicker.open ? /* @__PURE__ */ jsx81(
35689
+ ToolsPicker,
35690
+ {
35691
+ items: state.toolsPicker.items,
35692
+ selected: state.toolsPicker.selected,
35693
+ busy: state.toolsPicker.busy,
35694
+ hint: state.toolsPicker.hint,
35695
+ filter: state.toolsPicker.filter
35696
+ }
35697
+ ) : null,
35698
+ state.brainPanel.open && !state.modelPicker.open ? /* @__PURE__ */ jsx81(BrainPanel, { ...state.brainPanel }) : null,
35699
+ state.helpPanel.open ? /* @__PURE__ */ jsx81(
35700
+ HelpPanel,
35701
+ {
35702
+ entries: state.helpPanel.entries,
35703
+ filter: state.helpPanel.filter,
35704
+ selected: state.helpPanel.selected,
35705
+ hint: state.helpPanel.hint
35706
+ }
35707
+ ) : null,
35708
+ state.shadowPanel.open ? /* @__PURE__ */ jsx81(ShadowPanel, { shadow: state.shadowPanel.shadow, hint: state.shadowPanel.hint }) : null,
35709
+ state.authPanel.open ? /* @__PURE__ */ jsx81(AuthPanel, { panel: state.authPanel }) : null,
35710
+ state.projectPicker.open ? /* @__PURE__ */ jsx81(
35711
+ ProjectPicker,
35712
+ {
35713
+ items: state.projectPicker.items,
35714
+ selected: state.projectPicker.selected,
35715
+ filter: state.projectPicker.filter,
35716
+ hint: state.projectPicker.hint
35717
+ }
35718
+ ) : null,
35719
+ state.fKeyPicker.open ? /* @__PURE__ */ jsx81(FKeyPicker, { selected: state.fKeyPicker.selected }) : null,
35720
+ state.coordinator.monitorOpen ? /* @__PURE__ */ jsx81(
35721
+ CoordinatorPanel,
35722
+ {
35723
+ coordinator: state.coordinator,
35724
+ nowTick,
35725
+ onClose: () => dispatch({ type: "toggleCoordinatorMonitor" })
35726
+ }
35727
+ ) : null,
35728
+ state.auditPanelOpen ? /* @__PURE__ */ jsx81(
35729
+ AuditPanel,
35730
+ {
35731
+ sideEffects: agent.ctx.sideEffects ?? [],
35732
+ onClose: () => dispatch({ type: "toggleAuditPanel" })
35733
+ }
35734
+ ) : null,
35735
+ state.connectionsPanelOpen ? /* @__PURE__ */ jsx81(
35736
+ ConnectionsPanel,
35737
+ {
35738
+ projectRoot: agent.ctx.projectRoot,
35739
+ onClose: () => dispatch({ type: "toggleConnectionsPanel" })
35740
+ }
35741
+ ) : null,
35742
+ state.rewindOverlay ? (() => {
35743
+ const overlay = state.rewindOverlay;
35744
+ return /* @__PURE__ */ jsx81(
35745
+ CheckpointTimeline,
35746
+ {
35747
+ checkpoints: overlay.checkpoints,
35748
+ selected: overlay.selected,
35749
+ onSelect: (i) => dispatch({ type: "rewindOverlayMove", delta: i - overlay.selected }),
35750
+ onConfirm: (i) => {
35751
+ const checkpoint = overlay.checkpoints[i];
35752
+ if (checkpoint) handleRewindTo(checkpoint.promptIndex);
35753
+ },
35754
+ onClose: () => dispatch({ type: "rewindOverlayClose" })
35755
+ }
35756
+ );
35757
+ })() : null,
35758
+ state.brainPrompt ? /* @__PURE__ */ jsx81(Box, { flexDirection: "column", marginY: 1, flexShrink: 0, children: /* @__PURE__ */ jsx81(
35759
+ BrainDecisionPrompt,
35760
+ {
35761
+ ...state.brainPrompt,
35762
+ onAnswer: (answer) => {
35763
+ events.emit("brain.human_answered", { ...answer, at: Date.now() });
35764
+ dispatch({ type: "brainPromptClear" });
35765
+ }
35766
+ }
35767
+ ) }) : null,
35768
+ state.shellCommandWarning ? (() => {
35769
+ const info = state.shellCommandWarning;
35770
+ let resolved = false;
35771
+ const onDecision = (decision) => {
35772
+ if (resolved) return;
35773
+ resolved = true;
35774
+ info.resolve(decision);
35775
+ dispatch({ type: "shellCommandWarningClose" });
35776
+ };
35777
+ return /* @__PURE__ */ jsx81(ShellCommandWarning, { command: info.command, onDecision });
35778
+ })() : null,
35779
+ state.confirmQueue.length > 0 && (() => {
35780
+ const head = expectDefined5(state.confirmQueue[0]);
35781
+ let resolved = false;
35782
+ const onDecision = (decision) => {
35783
+ if (resolved) return;
35784
+ resolved = true;
35785
+ head.resolve(decision);
35786
+ dispatch({ type: "confirmClose" });
35787
+ };
35788
+ const onEnableYolo = () => {
35789
+ if (resolved) return;
35790
+ onYolo?.(true);
35791
+ setYoloLive(true);
35792
+ const cur = getSettings?.();
35793
+ if (cur && saveSettings) {
35794
+ Promise.resolve(saveSettings({ ...cur, yolo: true })).catch(() => {
35795
+ });
35796
+ }
35797
+ resolved = true;
35798
+ head.resolve("yes");
35799
+ dispatch({ type: "confirmClose" });
35800
+ };
35801
+ return /* @__PURE__ */ jsx81(
35802
+ ConfirmPrompt,
35803
+ {
35804
+ toolName: head.toolName,
35805
+ input: head.input,
35806
+ suggestedPattern: head.suggestedPattern,
35807
+ onDecision,
35808
+ onEnableYolo,
35809
+ destructive: head.destructive,
35810
+ boundaryReason: head.boundaryReason
35811
+ }
35812
+ );
35813
+ })(),
35814
+ state.clearConfirm ? /* @__PURE__ */ jsx81(
35815
+ ClearConfirmPanel,
35816
+ {
35817
+ leaderActive: state.clearConfirm.leaderActive,
35818
+ subagentCount: state.clearConfirm.subagentCount,
35819
+ value: state.clearConfirm.value
35820
+ }
35821
+ ) : null,
35822
+ state.exitConfirm ? /* @__PURE__ */ jsx81(
35823
+ ExitConfirmPanel,
35824
+ {
35825
+ leaderActive: state.exitConfirm.leaderActive,
35826
+ subagentCount: state.exitConfirm.subagentCount,
35827
+ backgroundCount: state.exitConfirm.backgroundCount
35828
+ }
35829
+ ) : null,
35830
+ state.slashConfirm ? /* @__PURE__ */ jsx81(
35831
+ SlashConfirmPanel,
35832
+ {
35833
+ question: state.slashConfirm.question,
35834
+ defaultYes: state.slashConfirm.defaultYes
35835
+ }
35836
+ ) : null,
35837
+ state.escConfirm ? /* @__PURE__ */ jsx81(Box, { flexDirection: "column", marginY: 1, flexShrink: 0, children: /* @__PURE__ */ jsx81(
35838
+ EscConfirmPrompt,
35839
+ {
35840
+ runningTools: state.escConfirm.snapshot.runningTools,
35841
+ subagentCount: state.escConfirm.snapshot.subagentsTerminated,
35842
+ onConfirm: () => {
35843
+ const escConfirm = state.escConfirm;
35844
+ if (!escConfirm) return;
35845
+ const { snapshot } = escConfirm;
35846
+ activeCtrlRef.current?.abort("user interrupt (Esc)");
35847
+ clearPendingConfirms();
35848
+ dispatch({ type: "status", status: "aborting" });
35849
+ dispatch({ type: "steerStart", snapshot });
35850
+ const escConfirmDir = liveDirector();
35851
+ if (escConfirmDir && snapshot.subagentsTerminated > 0) {
35852
+ const cap = new Promise((resolve) => {
35853
+ const t = setTimeout(resolve, 1500);
35854
+ t.unref?.();
35855
+ });
35856
+ void Promise.race([escConfirmDir.terminateAll().catch(() => void 0), cap]);
35857
+ }
35858
+ const droppedCount = state.queue.length;
35859
+ if (droppedCount > 0) dispatch({ type: "queueClear" });
35860
+ const droppedTag = droppedCount > 0 ? ` \xB7 dropped ${droppedCount} queued` : "";
35861
+ const fleetTag = snapshot.subagentsTerminated > 0 ? ` \xB7 stopped ${snapshot.subagentsTerminated} subagent${snapshot.subagentsTerminated === 1 ? "" : "s"}` : "";
35862
+ dispatch({
35863
+ type: "addEntry",
35864
+ entry: {
35865
+ kind: "warn",
35866
+ text: `\u21AF Interrupted${droppedTag}${fleetTag}. Type your new direction.`
35867
+ }
35868
+ });
35869
+ dispatch({ type: "escConfirmClose" });
35870
+ },
35871
+ onCancel: () => {
35872
+ dismissedEscAtRef.current = Date.now();
35873
+ dispatch({ type: "escConfirmClose" });
35874
+ }
35875
+ }
35876
+ ) }) : null,
35877
+ state.sendModePicker ? (() => {
35878
+ const info = state.sendModePicker;
35879
+ let resolved = false;
35880
+ const finish = (decision) => {
35881
+ if (resolved) return;
35882
+ resolved = true;
35883
+ info.resolve(decision);
35884
+ };
35885
+ return /* @__PURE__ */ jsx81(
35886
+ SendModePicker,
35887
+ {
35888
+ selected: info.selected,
35889
+ messagePreview: info.displayText,
35890
+ onMove: (delta) => dispatch({ type: "sendModePickerMove", delta }),
35891
+ onSelect: finish
35892
+ }
35893
+ );
35894
+ })() : null,
35895
+ state.refineCountdown ? (() => {
35896
+ const info = state.refineCountdown;
35897
+ let resolved = false;
35898
+ const onDecision = (decision) => {
35899
+ if (resolved) return;
35900
+ resolved = true;
35901
+ info.resolve(decision);
35902
+ };
35903
+ return /* @__PURE__ */ jsx81(
35904
+ RefineCountdownPanel,
35905
+ {
35906
+ original: info.original,
35907
+ seconds: info.seconds,
35908
+ onDecision,
35909
+ providerId: refineProviderId ?? agent.ctx.provider?.id,
35910
+ model: refineModel ?? agent.ctx.model
35911
+ }
35912
+ );
35913
+ })() : null,
35914
+ state.enhanceBusy && !state.enhance ? /* @__PURE__ */ jsx81(
35915
+ RefiningPanel,
35916
+ {
35917
+ original: enhanceOriginalRef.current,
35918
+ elapsedMs: enhanceStartedAt === null ? 0 : Math.max(0, Date.now() - enhanceStartedAt),
35919
+ pulseFrame: enhanceDots,
35920
+ providerId: refineProviderId ?? agent.ctx.provider?.id,
35921
+ model: refineModel ?? agent.ctx.model
35922
+ }
35923
+ ) : null,
35924
+ state.enhance ? (() => {
35925
+ const info = state.enhance;
35926
+ let resolved = false;
35927
+ const onDecision = (decision) => {
35928
+ if (resolved) return;
35929
+ resolved = true;
35930
+ setEnhanceCountdown(null);
35931
+ info.resolve(decision);
35932
+ };
35933
+ return /* @__PURE__ */ jsx81(
35934
+ EnhancePanel,
35935
+ {
35936
+ original: info.original,
35937
+ refined: info.refined,
35938
+ english: info.english,
35939
+ durationMs: enhanceDurationMs ?? 0,
35940
+ delayMs: enhanceDelayMs,
35941
+ enhanceLanguage: state.settingsPicker.enhanceLanguage,
35942
+ onDecision,
35943
+ onTick: (r) => setEnhanceCountdown(r > 0 ? r : null),
35944
+ providerId: refineProviderId ?? agent.ctx.provider?.id,
35945
+ model: refineModel ?? agent.ctx.model
35946
+ }
35947
+ );
35948
+ })() : null,
35949
+ state.refineFailure ? (() => {
35950
+ const info = state.refineFailure;
35951
+ let resolved = false;
35952
+ const onDecision = (decision) => {
35953
+ if (resolved) return;
35954
+ resolved = true;
35955
+ info.resolve(decision);
35956
+ };
35957
+ return /* @__PURE__ */ jsx81(
35958
+ RefineFailurePanel,
35959
+ {
35960
+ original: info.original,
35961
+ error: info.error,
35962
+ elapsedMs: info.elapsedMs,
35963
+ fallbackRef: info.fallbackRef,
35964
+ models: info.models,
35965
+ onDecision
35966
+ }
35967
+ );
35968
+ })() : null,
35969
+ state.continueConfirm ? (() => {
35970
+ const info = state.continueConfirm;
35971
+ let resolved = false;
35972
+ const onDecision = (decision) => {
35973
+ if (resolved) return;
35974
+ resolved = true;
35975
+ info.resolve(decision);
35976
+ };
35977
+ return /* @__PURE__ */ jsx81(
35978
+ ContinueConfirmPanel,
35979
+ {
35980
+ label: info.label,
35981
+ instruction: info.instruction,
35982
+ source: info.source,
35983
+ grounded: info.grounded,
35984
+ delayMs: CONTINUE_CONFIRM_DELAY_MS,
35985
+ onDecision
35986
+ }
35987
+ );
35988
+ })() : null,
35989
+ /* @__PURE__ */ jsx81(AppStatusRegion, { host, runtime, mainColumnWidth })
35990
+ ] })
35991
+ ] }),
35992
+ sidebarWidth > 0 ? /* @__PURE__ */ jsx81(RightSidebar, { width: sidebarWidth, maxHeight: runtime.termRows, focused: state.sidebarFocused, children: /* @__PURE__ */ jsx81(
35993
+ SidebarContent,
35994
+ {
35995
+ contextWindow: statusbar.contextWindow,
35996
+ entries: statusbar.entriesWithLeader,
35997
+ fleetCounts: statusbar.fleetCounts,
35998
+ provider: liveProvider,
35999
+ model: liveModel,
36000
+ width: sidebarWidth,
36001
+ scrollOffset: state.sidebarScrollOffset,
36002
+ focused: state.sidebarFocused,
36003
+ todos: liveTodos,
36004
+ showSwarmSection: state.settingsPicker.open ? state.settingsPicker.showAgentSwarmPanel === "sidebar" : (liveSettings?.showAgentSwarmPanel ?? "bottom") === "sidebar",
36005
+ liveSessions: state.sessionsPanel.sessions,
36006
+ resumeSessions: state.resumePicker.sessions,
36007
+ currentSessionId: agent.ctx.session?.id
36008
+ }
36009
+ ) }) : null
35084
36010
  ] })
35085
36011
  }
35086
36012
  )
@@ -36461,7 +37387,7 @@ function routeSettingsOverlayKey(host, input, key, isEnter) {
36461
37387
  enhanceEnabled: config.enhanceEnabled ?? true,
36462
37388
  enhanceLanguage: config.enhanceLanguage ?? "original",
36463
37389
  debugStream: config.debugStream ?? false,
36464
- statuslineMode: config.statuslineMode ?? "detailed",
37390
+ statuslineMode: config.statuslineMode ?? DEFAULT_STATUSLINE_MODE,
36465
37391
  reasoningMode: config.reasoningMode ?? "auto",
36466
37392
  reasoningEffort: config.reasoningEffort ?? "high",
36467
37393
  reasoningPreserve: config.reasoningPreserve ?? false,
@@ -36472,7 +37398,7 @@ function routeSettingsOverlayKey(host, input, key, isEnter) {
36472
37398
  breakerEnabled: config.breakerEnabled ?? false,
36473
37399
  breakerAutoKillResetMs: config.breakerAutoKillResetMs ?? 6e4,
36474
37400
  showModelReasoning: config.showModelReasoning ?? true,
36475
- showAgentSwarmPanel: config.showAgentSwarmPanel ?? true,
37401
+ showAgentSwarmPanel: coerceAgentSwarmMode(config.showAgentSwarmPanel),
36476
37402
  showSageMemoryInject: config.showSageMemoryInject ?? false,
36477
37403
  sageMemoryInjectThreshold: config.sageMemoryInjectThreshold ?? 0.85,
36478
37404
  readSymbols: config.readSymbols ?? false
@@ -36629,6 +37555,7 @@ function createAppKeyHandler(options) {
36629
37555
  termRows,
36630
37556
  terminalColumns,
36631
37557
  terminalRows,
37558
+ mainColumnWidth,
36632
37559
  statusBarWrapRef,
36633
37560
  belowStatusBarRef,
36634
37561
  liveStatuslineMode,
@@ -36654,6 +37581,7 @@ function createAppKeyHandler(options) {
36654
37581
  onHistoryCopy
36655
37582
  } = options;
36656
37583
  const stdout = { columns: terminalColumns, rows: terminalRows };
37584
+ const historyWidth = mainColumnWidth > 0 ? mainColumnWidth : stdout?.columns ?? 80;
36657
37585
  const handleKey = async (input, key) => {
36658
37586
  if (key.ctrl && (input === "c" || input === "C" || input === "")) {
36659
37587
  runInterruptLadder();
@@ -36682,6 +37610,9 @@ function createAppKeyHandler(options) {
36682
37610
  lastEscAtRef.current = now;
36683
37611
  }
36684
37612
  if (input) {
37613
+ if (state.sidebarFocused) {
37614
+ dispatch({ type: "toggleSidebarFocus" });
37615
+ }
36685
37616
  const paste = feedPaste(pasteAccumRef.current, input);
36686
37617
  if (paste) {
36687
37618
  pasteAccumRef.current = paste.accum;
@@ -36738,7 +37669,7 @@ function createAppKeyHandler(options) {
36738
37669
  dispatch({ type: "toggleSddBoardMonitor" });
36739
37670
  return;
36740
37671
  }
36741
- if (key.ctrl && input === "j") {
37672
+ if (key.ctrl && input === "y") {
36742
37673
  dispatch({ type: "toggleKanbanPanel" });
36743
37674
  return;
36744
37675
  }
@@ -36778,7 +37709,7 @@ function createAppKeyHandler(options) {
36778
37709
  }
36779
37710
  }
36780
37711
  }
36781
- if (state.sddBoard?.monitorOpen && !key.ctrl && !key.meta) {
37712
+ if (state.sddBoard?.monitorOpen && !key.ctrl && !key.meta && draftRef.current.buffer === "") {
36782
37713
  if (key.rightArrow) {
36783
37714
  dispatch({ type: "sddBoardFocusNext" });
36784
37715
  return;
@@ -36820,6 +37751,27 @@ function createAppKeyHandler(options) {
36820
37751
  }
36821
37752
  if (routePanelEscapeKey(state, key, dispatch)) return;
36822
37753
  const overlayOpen = isLowerOverlayOpen(state);
37754
+ if (key.tab && key.shift && draftRef.current.buffer === "" && !overlayOpen) {
37755
+ dispatch({ type: "toggleSidebarFocus" });
37756
+ return;
37757
+ }
37758
+ if (state.sidebarFocused && !overlayOpen) {
37759
+ if (key.upArrow) {
37760
+ dispatch({ type: "sidebarScroll", delta: -1, viewportHeight: termRows - 2 });
37761
+ return;
37762
+ }
37763
+ if (key.downArrow) {
37764
+ dispatch({ type: "sidebarScroll", delta: 1, viewportHeight: termRows - 2 });
37765
+ return;
37766
+ }
37767
+ if (key.escape) {
37768
+ dispatch({ type: "toggleSidebarFocus" });
37769
+ return;
37770
+ }
37771
+ if (input) {
37772
+ dispatch({ type: "toggleSidebarFocus" });
37773
+ }
37774
+ }
36823
37775
  if (input === "?" && !key.ctrl && !key.meta && draftRef.current.buffer === "" && !overlayOpen) {
36824
37776
  dispatch({ type: "toggleHelp" });
36825
37777
  return;
@@ -36839,36 +37791,74 @@ function createAppKeyHandler(options) {
36839
37791
  return;
36840
37792
  }
36841
37793
  if (!overlayOpen) {
37794
+ if (mouseMode && key.mouse?.kind === "press" && key.mouse.button === "right") {
37795
+ const region = hitRegion(
37796
+ { termRows, termCols: historyWidth, viewportRows: state.viewportRows },
37797
+ key.mouse.x,
37798
+ key.mouse.y
37799
+ );
37800
+ if (region?.kind === "history" && key.mouse.x <= historyWidth - SCROLLBAR_HIT_WIDTH) {
37801
+ void historyScrollRef.current?.commitSelection().then((copied) => {
37802
+ if (copied) onHistoryCopy?.(SELECTION_COPY_ID);
37803
+ });
37804
+ return;
37805
+ }
37806
+ historyScrollRef.current?.clearSelection();
37807
+ }
36842
37808
  if (key.mouse?.kind === "wheel" && key.mouse.wheel !== 0) {
37809
+ if (historyWidth < (stdout?.columns ?? 80) && key.mouse.x > historyWidth && state.sidebarFocused) {
37810
+ dispatch({
37811
+ type: "sidebarScroll",
37812
+ delta: key.mouse.wheel > 0 ? -1 : 1,
37813
+ viewportHeight: termRows - 2
37814
+ });
37815
+ return;
37816
+ }
36843
37817
  if (isHistoryScrollTarget(
36844
- { termRows, termCols: stdout?.columns ?? 80, viewportRows: state.viewportRows },
37818
+ { termRows, termCols: historyWidth, viewportRows: state.viewportRows },
36845
37819
  key.mouse.x,
36846
37820
  key.mouse.y
36847
37821
  )) {
36848
37822
  if (key.mouse.shift)
36849
37823
  historyScrollRef.current?.scrollPage(key.mouse.wheel > 0 ? "up" : "down");
36850
37824
  else historyScrollRef.current?.scrollBy(key.mouse.wheel > 0 ? 1 : -1);
37825
+ historyScrollRef.current?.clearSelection();
36851
37826
  return;
36852
37827
  }
36853
37828
  }
36854
37829
  if ((key.mouse?.kind === "press" || mouseMode && key.mouse?.kind === "move") && key.mouse.button === "left") {
36855
37830
  const region = hitRegion(
36856
- { termRows, termCols: stdout?.columns ?? 80, viewportRows: state.viewportRows },
37831
+ { termRows, termCols: historyWidth, viewportRows: state.viewportRows },
36857
37832
  key.mouse.x,
36858
37833
  key.mouse.y
36859
37834
  );
36860
37835
  const copyRow = region?.kind === "history" ? region.row : region?.kind === "scrollbar" ? region.cell : null;
36861
37836
  if (copyRow !== null && key.mouse.kind === "press" && historyScrollRef.current?.hasCopyTargetAt(copyRow, key.mouse.x - 1)) {
37837
+ historyScrollRef.current?.clearSelection();
36862
37838
  void historyScrollRef.current.copyAtViewportCell(copyRow, key.mouse.x - 1).then((entryId) => {
36863
37839
  if (entryId !== null) onHistoryCopy?.(entryId);
36864
37840
  }).catch(() => null);
36865
37841
  return;
36866
37842
  }
37843
+ if (mouseMode && region?.kind === "history" && key.mouse.x <= historyWidth - SCROLLBAR_HIT_WIDTH) {
37844
+ if (key.mouse.kind === "press") {
37845
+ historyScrollRef.current?.beginSelection(region.row, key.mouse.x - 1);
37846
+ return;
37847
+ }
37848
+ if (key.mouse.kind === "move") {
37849
+ historyScrollRef.current?.extendSelection(region.row, key.mouse.x - 1);
37850
+ return;
37851
+ }
37852
+ }
36867
37853
  if (region?.kind === "scrollbar") {
37854
+ historyScrollRef.current?.clearSelection();
36868
37855
  historyScrollRef.current?.scrollToTrackCell(region.cell);
36869
37856
  return;
36870
37857
  }
36871
37858
  }
37859
+ if (mouseMode && key.mouse?.kind === "release" && key.mouse.button === "left") {
37860
+ historyScrollRef.current?.endSelection();
37861
+ }
36872
37862
  if (mouseMode && key.mouse?.kind === "press" && key.mouse.button === "left" && statusBarWrapRef.current) {
36873
37863
  const sbHeight = measureElement(statusBarWrapRef.current).height;
36874
37864
  const belowHeight = belowStatusBarRef.current ? measureElement(belowStatusBarRef.current).height : 0;
@@ -37007,7 +37997,7 @@ function createAppKeyHandler(options) {
37007
37997
 
37008
37998
  // src/app.tsx
37009
37999
  import { buildGoalPreamble as buildGoalPreamble2 } from "@wrongstack/core/execution";
37010
- import { jsx as jsx79 } from "react/jsx-runtime";
38000
+ import { jsx as jsx82 } from "react/jsx-runtime";
37011
38001
  function App(props) {
37012
38002
  const {
37013
38003
  agent,
@@ -37740,6 +38730,14 @@ function App(props) {
37740
38730
  termRows,
37741
38731
  terminalColumns: stdout?.columns ?? 80,
37742
38732
  terminalRows: stdout?.rows ?? 24,
38733
+ mainColumnWidth: (() => {
38734
+ const cols = stdout?.columns ?? 80;
38735
+ const sw = computeSidebarWidth(cols);
38736
+ if (sw === 0 || isPickerOverlayOpen(state) || state.coordinator.monitorOpen || state.auditPanelOpen || state.connectionsPanelOpen || state.helpOpen || state.agentsMonitorOpen || state.monitorOpen || state.contextPanelOpen || state.processListOpen || state.todosMonitorOpen || state.worktreeMonitorOpen || state.planPanelOpen || state.kanbanPanelOpen || state.queuePanelOpen || state.goalPanelOpen || state.goalKanbanPanelOpen || state.cronMonitorOpen) {
38737
+ return cols;
38738
+ }
38739
+ return cols - sw;
38740
+ })(),
37743
38741
  statusBarWrapRef,
37744
38742
  belowStatusBarRef,
37745
38743
  liveStatuslineMode,
@@ -37912,7 +38910,7 @@ function App(props) {
37912
38910
  fleetRunning: fleetCounts?.running ?? 0,
37913
38911
  liveAnimationStyle
37914
38912
  });
37915
- return /* @__PURE__ */ jsx79(
38913
+ return /* @__PURE__ */ jsx82(
37916
38914
  AppView,
37917
38915
  {
37918
38916
  host: props,
@@ -38343,6 +39341,7 @@ var origConsoleInfo = console.info;
38343
39341
  var origConsoleTable = console.table;
38344
39342
  var origConsoleTrace = console.trace;
38345
39343
  var origStderrWrite = process.stderr.write.bind(process.stderr);
39344
+ var origStdoutWrite = process.stdout.write.bind(process.stdout);
38346
39345
  var consoleNoop = (..._args) => {
38347
39346
  };
38348
39347
  var stderrNoop = ((_chunk, _encodingOrCb, _cb) => {
@@ -38372,6 +39371,7 @@ function unsilenceTerminal() {
38372
39371
  console.table = origConsoleTable;
38373
39372
  console.trace = origConsoleTrace;
38374
39373
  process.stderr.write = origStderrWrite;
39374
+ process.stdout.write = origStdoutWrite;
38375
39375
  process.off("warning", warningNoop);
38376
39376
  }
38377
39377
 
@@ -38389,6 +39389,10 @@ async function runTui(opts) {
38389
39389
  const capability = detectTerminal({ stdin, stdout });
38390
39390
  const mouseEnabled = opts.mouse ?? opts.getSettings?.().mouseMode ?? process.env.WRONGSTACK_MOUSE === "1";
38391
39391
  silenceTerminal();
39392
+ const provider = opts.agent.ctx.provider;
39393
+ if (provider?.suppressMaxToolsWarning) {
39394
+ provider.suppressMaxToolsWarning();
39395
+ }
38392
39396
  const inkStdin = stdin;
38393
39397
  const {
38394
39398
  controller: titleController,