@wrongstack/tui 0.297.0 → 0.298.0

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 (292) hide show
  1. package/dist/app-action-type.d.ts +10 -1
  2. package/dist/app-props.d.ts +11 -1
  3. package/dist/app-settings-type.d.ts +1 -1
  4. package/dist/components/auth-panel.d.ts +4 -0
  5. package/dist/components/confirm-prompt.d.ts +14 -0
  6. package/dist/components/scrollable-history.d.ts +200 -1
  7. package/dist/components/settings-picker-model.d.ts +10 -0
  8. package/dist/components/status-bar-types.d.ts +31 -5
  9. package/dist/components/status-bar.d.ts +1 -1
  10. package/dist/hooks/use-statusbar-view-model.d.ts +1 -0
  11. package/dist/hooks/use-tui-slash-commands.d.ts +1 -1
  12. package/dist/index.js +521 -103
  13. package/dist/markdown.d.ts +2 -0
  14. package/dist/run-tui-options.d.ts +10 -1
  15. package/dist/token-previews.d.ts +3 -2
  16. package/package.json +10 -8
  17. package/dist/app-action-type.d.ts.map +0 -1
  18. package/dist/app-initial-state.d.ts.map +0 -1
  19. package/dist/app-key-handler.d.ts.map +0 -1
  20. package/dist/app-props.d.ts.map +0 -1
  21. package/dist/app-reducer.d.ts.map +0 -1
  22. package/dist/app-settings-type.d.ts.map +0 -1
  23. package/dist/app-state-core-types.d.ts.map +0 -1
  24. package/dist/app-state-fleet.d.ts.map +0 -1
  25. package/dist/app-state.d.ts.map +0 -1
  26. package/dist/app-status-region.d.ts.map +0 -1
  27. package/dist/app-ui-state.d.ts.map +0 -1
  28. package/dist/app-view-contract.d.ts.map +0 -1
  29. package/dist/app-view-state.d.ts.map +0 -1
  30. package/dist/app-view.d.ts.map +0 -1
  31. package/dist/app.d.ts.map +0 -1
  32. package/dist/auth-panel-model.d.ts.map +0 -1
  33. package/dist/brain-contracts.d.ts.map +0 -1
  34. package/dist/brain-panel-model.d.ts.map +0 -1
  35. package/dist/checkpoint-retention.d.ts.map +0 -1
  36. package/dist/clipboard.d.ts.map +0 -1
  37. package/dist/components/agents-monitor-constants.d.ts.map +0 -1
  38. package/dist/components/agents-monitor.d.ts.map +0 -1
  39. package/dist/components/animation-style.d.ts.map +0 -1
  40. package/dist/components/audit-panel.d.ts.map +0 -1
  41. package/dist/components/auth-panel-model.d.ts.map +0 -1
  42. package/dist/components/auth-panel.d.ts.map +0 -1
  43. package/dist/components/autonomy-picker.d.ts.map +0 -1
  44. package/dist/components/brain-decision-prompt.d.ts.map +0 -1
  45. package/dist/components/brain-panel-model.d.ts.map +0 -1
  46. package/dist/components/brain-panel.d.ts.map +0 -1
  47. package/dist/components/checkpoint-timeline.d.ts.map +0 -1
  48. package/dist/components/clear-confirm-panel.d.ts.map +0 -1
  49. package/dist/components/composer-status-chip.d.ts.map +0 -1
  50. package/dist/components/confirm-prompt.d.ts.map +0 -1
  51. package/dist/components/connections-panel.d.ts.map +0 -1
  52. package/dist/components/context-panel.d.ts.map +0 -1
  53. package/dist/components/continue-confirm-panel.d.ts.map +0 -1
  54. package/dist/components/coordinator-panel.d.ts.map +0 -1
  55. package/dist/components/cron-jobs.d.ts.map +0 -1
  56. package/dist/components/design-picker.d.ts.map +0 -1
  57. package/dist/components/enhance-panel.d.ts.map +0 -1
  58. package/dist/components/entry-error-boundary.d.ts.map +0 -1
  59. package/dist/components/esc-confirm-prompt.d.ts.map +0 -1
  60. package/dist/components/exit-confirm-panel.d.ts.map +0 -1
  61. package/dist/components/f-key-picker.d.ts.map +0 -1
  62. package/dist/components/file-picker.d.ts.map +0 -1
  63. package/dist/components/fleet-monitor.d.ts.map +0 -1
  64. package/dist/components/fleet-panel.d.ts.map +0 -1
  65. package/dist/components/goal-kanban-panel.d.ts.map +0 -1
  66. package/dist/components/goal-panel.d.ts.map +0 -1
  67. package/dist/components/help-overlay.d.ts.map +0 -1
  68. package/dist/components/help-panel.d.ts.map +0 -1
  69. package/dist/components/history/assistant.d.ts.map +0 -1
  70. package/dist/components/history/banner.d.ts.map +0 -1
  71. package/dist/components/history/basic-format.d.ts.map +0 -1
  72. package/dist/components/history/code-block-diff-helpers.d.ts.map +0 -1
  73. package/dist/components/history/code-block.d.ts.map +0 -1
  74. package/dist/components/history/copy-icon.d.ts.map +0 -1
  75. package/dist/components/history/entry.d.ts.map +0 -1
  76. package/dist/components/history/index.d.ts.map +0 -1
  77. package/dist/components/history/replay.d.ts.map +0 -1
  78. package/dist/components/history/sage-output-format.d.ts.map +0 -1
  79. package/dist/components/history/stream-box.d.ts.map +0 -1
  80. package/dist/components/history/tool-arg-format.d.ts.map +0 -1
  81. package/dist/components/history/tool-card.d.ts.map +0 -1
  82. package/dist/components/history/tool-group.d.ts.map +0 -1
  83. package/dist/components/history/tool-output-summary.d.ts.map +0 -1
  84. package/dist/components/history/tool-visual-command.d.ts.map +0 -1
  85. package/dist/components/history/tool-visual-domain.d.ts.map +0 -1
  86. package/dist/components/history/tool-visual-format.d.ts.map +0 -1
  87. package/dist/components/history/tool-visual-lsp.d.ts.map +0 -1
  88. package/dist/components/history/tool-visual-misc.d.ts.map +0 -1
  89. package/dist/components/history/tool-visual-mode-workdir.d.ts.map +0 -1
  90. package/dist/components/history/tool-visual-types.d.ts.map +0 -1
  91. package/dist/components/history/types.d.ts.map +0 -1
  92. package/dist/components/history/utils.d.ts.map +0 -1
  93. package/dist/components/history/visual-lines.d.ts.map +0 -1
  94. package/dist/components/history/visual-memory-logs.d.ts.map +0 -1
  95. package/dist/components/history.d.ts.map +0 -1
  96. package/dist/components/input.d.ts.map +0 -1
  97. package/dist/components/kanban-panel.d.ts.map +0 -1
  98. package/dist/components/key-hint-bar.d.ts.map +0 -1
  99. package/dist/components/live-activity-strip.d.ts.map +0 -1
  100. package/dist/components/mailbox-panel.d.ts.map +0 -1
  101. package/dist/components/mcp-picker.d.ts.map +0 -1
  102. package/dist/components/memory-context-widget.d.ts.map +0 -1
  103. package/dist/components/mode-picker.d.ts.map +0 -1
  104. package/dist/components/model-picker.d.ts.map +0 -1
  105. package/dist/components/monitor-shell.d.ts.map +0 -1
  106. package/dist/components/phase-monitor.d.ts.map +0 -1
  107. package/dist/components/phase-panel.d.ts.map +0 -1
  108. package/dist/components/plan-panel.d.ts.map +0 -1
  109. package/dist/components/plugin-picker.d.ts.map +0 -1
  110. package/dist/components/powerline-rail.d.ts.map +0 -1
  111. package/dist/components/process-list.d.ts.map +0 -1
  112. package/dist/components/project-picker.d.ts.map +0 -1
  113. package/dist/components/prompt-picker.d.ts.map +0 -1
  114. package/dist/components/provider-colors.d.ts.map +0 -1
  115. package/dist/components/queue-panel.d.ts.map +0 -1
  116. package/dist/components/refine-countdown-panel.d.ts.map +0 -1
  117. package/dist/components/refine-failure-panel.d.ts.map +0 -1
  118. package/dist/components/resume-picker.d.ts.map +0 -1
  119. package/dist/components/scrollable-history.d.ts.map +0 -1
  120. package/dist/components/sdd-board-overlay.d.ts.map +0 -1
  121. package/dist/components/send-mode-picker.d.ts.map +0 -1
  122. package/dist/components/sessions-panel.d.ts.map +0 -1
  123. package/dist/components/settings-picker-filter.d.ts.map +0 -1
  124. package/dist/components/settings-picker-jumps.d.ts.map +0 -1
  125. package/dist/components/settings-picker-model.d.ts.map +0 -1
  126. package/dist/components/settings-picker-row-list.d.ts.map +0 -1
  127. package/dist/components/settings-picker.d.ts.map +0 -1
  128. package/dist/components/shadow-panel.d.ts.map +0 -1
  129. package/dist/components/shell-command-warning.d.ts.map +0 -1
  130. package/dist/components/slash-confirm-panel.d.ts.map +0 -1
  131. package/dist/components/slash-menu.d.ts.map +0 -1
  132. package/dist/components/status-bar-chips.d.ts.map +0 -1
  133. package/dist/components/status-bar-format.d.ts.map +0 -1
  134. package/dist/components/status-bar-helpers.d.ts.map +0 -1
  135. package/dist/components/status-bar-types.d.ts.map +0 -1
  136. package/dist/components/status-bar.d.ts.map +0 -1
  137. package/dist/components/statusline-detail-panel.d.ts.map +0 -1
  138. package/dist/components/statusline-picker.d.ts.map +0 -1
  139. package/dist/components/suggestions.d.ts.map +0 -1
  140. package/dist/components/todos-monitor.d.ts.map +0 -1
  141. package/dist/components/tools-picker.d.ts.map +0 -1
  142. package/dist/components/worktree-monitor.d.ts.map +0 -1
  143. package/dist/components/worktree-panel.d.ts.map +0 -1
  144. package/dist/connections-health.d.ts.map +0 -1
  145. package/dist/connections-slash.d.ts.map +0 -1
  146. package/dist/context-fill.d.ts.map +0 -1
  147. package/dist/context-slash.d.ts.map +0 -1
  148. package/dist/cron-slash.d.ts.map +0 -1
  149. package/dist/esc-close-panels.d.ts.map +0 -1
  150. package/dist/exit-slash.d.ts.map +0 -1
  151. package/dist/f-key-panels.d.ts.map +0 -1
  152. package/dist/file-search.d.ts.map +0 -1
  153. package/dist/fn-keys.d.ts.map +0 -1
  154. package/dist/git-info.d.ts.map +0 -1
  155. package/dist/heap-watchdog.d.ts.map +0 -1
  156. package/dist/height-cache.d.ts.map +0 -1
  157. package/dist/highlight.d.ts.map +0 -1
  158. package/dist/history-archive.d.ts.map +0 -1
  159. package/dist/history-entry.d.ts.map +0 -1
  160. package/dist/history-retention.d.ts.map +0 -1
  161. package/dist/hit-test.d.ts.map +0 -1
  162. package/dist/hooks/fleet-chat-coalescer.d.ts.map +0 -1
  163. package/dist/hooks/subagent-history-format.d.ts.map +0 -1
  164. package/dist/hooks/use-app-picker-keys.d.ts.map +0 -1
  165. package/dist/hooks/use-app-runtime-refs.d.ts.map +0 -1
  166. package/dist/hooks/use-app-session-state.d.ts.map +0 -1
  167. package/dist/hooks/use-auth-panel.d.ts.map +0 -1
  168. package/dist/hooks/use-autonomous-coordinator.d.ts.map +0 -1
  169. package/dist/hooks/use-autonomy-drivers.d.ts.map +0 -1
  170. package/dist/hooks/use-brain-events.d.ts.map +0 -1
  171. package/dist/hooks/use-brain-panel.d.ts.map +0 -1
  172. package/dist/hooks/use-brain-risk-sync.d.ts.map +0 -1
  173. package/dist/hooks/use-chip-staleness-guard.d.ts.map +0 -1
  174. package/dist/hooks/use-client-telemetry.d.ts.map +0 -1
  175. package/dist/hooks/use-core-tui-commands.d.ts.map +0 -1
  176. package/dist/hooks/use-director-fleet-bridge.d.ts.map +0 -1
  177. package/dist/hooks/use-enhance-runtime-state.d.ts.map +0 -1
  178. package/dist/hooks/use-exit-command.d.ts.map +0 -1
  179. package/dist/hooks/use-file-search.d.ts.map +0 -1
  180. package/dist/hooks/use-fleet-generation-gate.d.ts.map +0 -1
  181. package/dist/hooks/use-git-session-status.d.ts.map +0 -1
  182. package/dist/hooks/use-help-panel.d.ts.map +0 -1
  183. package/dist/hooks/use-history-copy-notice.d.ts.map +0 -1
  184. package/dist/hooks/use-history-viewport-sync.d.ts.map +0 -1
  185. package/dist/hooks/use-initial-prompt.d.ts.map +0 -1
  186. package/dist/hooks/use-input-history-persistence.d.ts.map +0 -1
  187. package/dist/hooks/use-interrupt-ladder.d.ts.map +0 -1
  188. package/dist/hooks/use-kanban-board-focus.d.ts.map +0 -1
  189. package/dist/hooks/use-live-settings-state.d.ts.map +0 -1
  190. package/dist/hooks/use-live-todos.d.ts.map +0 -1
  191. package/dist/hooks/use-mailbox-view-model.d.ts.map +0 -1
  192. package/dist/hooks/use-mode-picker.d.ts.map +0 -1
  193. package/dist/hooks/use-model-pick.d.ts.map +0 -1
  194. package/dist/hooks/use-mouse-tracking.d.ts.map +0 -1
  195. package/dist/hooks/use-next-steps-auto-submit.d.ts.map +0 -1
  196. package/dist/hooks/use-panel-controllers.d.ts.map +0 -1
  197. package/dist/hooks/use-paste-handling.d.ts.map +0 -1
  198. package/dist/hooks/use-picker-keys-types.d.ts.map +0 -1
  199. package/dist/hooks/use-picker-keys.d.ts.map +0 -1
  200. package/dist/hooks/use-prompt-picker.d.ts.map +0 -1
  201. package/dist/hooks/use-provider-event-bridge.d.ts.map +0 -1
  202. package/dist/hooks/use-queue-manager.d.ts.map +0 -1
  203. package/dist/hooks/use-session-interrupt-controller.d.ts.map +0 -1
  204. package/dist/hooks/use-settings-auto-save.d.ts.map +0 -1
  205. package/dist/hooks/use-shadow-panel.d.ts.map +0 -1
  206. package/dist/hooks/use-slash-picker.d.ts.map +0 -1
  207. package/dist/hooks/use-stable-key-handler.d.ts.map +0 -1
  208. package/dist/hooks/use-statusbar-view-model.d.ts.map +0 -1
  209. package/dist/hooks/use-statusline-hidden-sync.d.ts.map +0 -1
  210. package/dist/hooks/use-statusline-state.d.ts.map +0 -1
  211. package/dist/hooks/use-stream-chip-expiration.d.ts.map +0 -1
  212. package/dist/hooks/use-subagent-events.d.ts.map +0 -1
  213. package/dist/hooks/use-terminal-render-lifecycle.d.ts.map +0 -1
  214. package/dist/hooks/use-todos-auto-clear.d.ts.map +0 -1
  215. package/dist/hooks/use-token-counter-refresh.d.ts.map +0 -1
  216. package/dist/hooks/use-tui-activity.d.ts.map +0 -1
  217. package/dist/hooks/use-tui-controllers.d.ts.map +0 -1
  218. package/dist/hooks/use-tui-environment-state.d.ts.map +0 -1
  219. package/dist/hooks/use-tui-event-bridge.d.ts.map +0 -1
  220. package/dist/hooks/use-tui-slash-commands.d.ts.map +0 -1
  221. package/dist/hooks/use-working-dir-chip.d.ts.map +0 -1
  222. package/dist/index.d.ts.map +0 -1
  223. package/dist/index.js.map +0 -7
  224. package/dist/ink.d.ts.map +0 -1
  225. package/dist/input-editing.d.ts.map +0 -1
  226. package/dist/input-key-router.d.ts.map +0 -1
  227. package/dist/input-tokens.d.ts.map +0 -1
  228. package/dist/input-validation/action-helpers.d.ts.map +0 -1
  229. package/dist/input-validation/action-types.d.ts.map +0 -1
  230. package/dist/input-validation/allow-lists.d.ts.map +0 -1
  231. package/dist/input-validation/limits.d.ts.map +0 -1
  232. package/dist/input-validation/result.d.ts.map +0 -1
  233. package/dist/input-validation/state-entries.d.ts.map +0 -1
  234. package/dist/input-validation/terminal.d.ts.map +0 -1
  235. package/dist/input-validation.d.ts.map +0 -1
  236. package/dist/kanban-audit.d.ts.map +0 -1
  237. package/dist/kanban-slash.d.ts.map +0 -1
  238. package/dist/kill-slash.d.ts.map +0 -1
  239. package/dist/layout-engine.d.ts.map +0 -1
  240. package/dist/layout-store.d.ts.map +0 -1
  241. package/dist/mailbox-view-model-types.d.ts.map +0 -1
  242. package/dist/markdown-table.d.ts.map +0 -1
  243. package/dist/markdown.d.ts.map +0 -1
  244. package/dist/memory-context-monitor.d.ts.map +0 -1
  245. package/dist/memory-lifecycle-entry.d.ts.map +0 -1
  246. package/dist/memory-slash-format.d.ts.map +0 -1
  247. package/dist/memory-slash.d.ts.map +0 -1
  248. package/dist/mouse.d.ts.map +0 -1
  249. package/dist/on-panel-open.d.ts.map +0 -1
  250. package/dist/overlay-key-router.d.ts.map +0 -1
  251. package/dist/paste-accumulator.d.ts.map +0 -1
  252. package/dist/prompt-refinement-start.d.ts.map +0 -1
  253. package/dist/ps-slash.d.ts.map +0 -1
  254. package/dist/queue-slash.d.ts.map +0 -1
  255. package/dist/reducers/activity.d.ts.map +0 -1
  256. package/dist/reducers/composer.d.ts.map +0 -1
  257. package/dist/reducers/conversation.d.ts.map +0 -1
  258. package/dist/reducers/dialogs.d.ts.map +0 -1
  259. package/dist/reducers/fleet.d.ts.map +0 -1
  260. package/dist/reducers/helpers.d.ts.map +0 -1
  261. package/dist/reducers/panel-pickers.d.ts.map +0 -1
  262. package/dist/reducers/settings-panel.d.ts.map +0 -1
  263. package/dist/reducers/settings-values.d.ts.map +0 -1
  264. package/dist/reducers/workspace-panels.d.ts.map +0 -1
  265. package/dist/rehydrate-history.d.ts.map +0 -1
  266. package/dist/run-blocks-controller.d.ts.map +0 -1
  267. package/dist/run-tui-client-registration.d.ts.map +0 -1
  268. package/dist/run-tui-options.d.ts.map +0 -1
  269. package/dist/run-tui-title-controller.d.ts.map +0 -1
  270. package/dist/run-tui.d.ts.map +0 -1
  271. package/dist/running-tools.d.ts.map +0 -1
  272. package/dist/scroll-anchor.d.ts.map +0 -1
  273. package/dist/sdd-lifecycle-entry.d.ts.map +0 -1
  274. package/dist/settings-contracts.d.ts.map +0 -1
  275. package/dist/shared-types.d.ts.map +0 -1
  276. package/dist/slash-command-search.d.ts.map +0 -1
  277. package/dist/steering-preamble.d.ts.map +0 -1
  278. package/dist/submit-controller.d.ts.map +0 -1
  279. package/dist/submit-history.d.ts.map +0 -1
  280. package/dist/submit-prompt-refinement.d.ts.map +0 -1
  281. package/dist/terminal-modes.d.ts.map +0 -1
  282. package/dist/terminal-silence.d.ts.map +0 -1
  283. package/dist/terminal-title.d.ts.map +0 -1
  284. package/dist/terminal-width.d.ts.map +0 -1
  285. package/dist/theme.d.ts.map +0 -1
  286. package/dist/thinking-word.d.ts.map +0 -1
  287. package/dist/token-previews.d.ts.map +0 -1
  288. package/dist/tool-glyph.d.ts.map +0 -1
  289. package/dist/tui-host-capabilities.d.ts.map +0 -1
  290. package/dist/tui-memory-counters.d.ts.map +0 -1
  291. package/dist/ui-contracts.d.ts.map +0 -1
  292. 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) };
@@ -1380,12 +1379,16 @@ var COMFORTABLE_THRESHOLD = 90;
1380
1379
  function chipColor(color, isNoColor) {
1381
1380
  return isNoColor ? void 0 : color;
1382
1381
  }
1382
+ var STACK_ORANGE = "#FD9F02";
1383
1383
  var LINE_BG_COLORS = [theme.surface, theme.surface, theme.surface, theme.surface];
1384
1384
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1385
1385
  var SPINNER_INTERVAL_MS = 1e3;
1386
1386
  function StatusBar({
1387
1387
  model,
1388
1388
  provider,
1389
+ version,
1390
+ latestVersion,
1391
+ updateAvailable,
1389
1392
  state,
1390
1393
  thinkingWord,
1391
1394
  thinkingAnimationStyle,
@@ -1414,11 +1417,15 @@ function StatusBar({
1414
1417
  memoryContextMonitor,
1415
1418
  contextStrategy,
1416
1419
  hiddenItems,
1420
+ // Component-level fallback stays 'detailed' for back-compat with callers/tests
1421
+ // that omit `mode`. The user-facing default is 'minimum' (DEFAULT_STATUSLINE_MODE),
1422
+ // applied at the app/settings layer — not here.
1417
1423
  mode = "detailed",
1418
1424
  events,
1419
1425
  sessionId,
1420
1426
  eternalStage,
1421
1427
  goalSummary,
1428
+ droppedTools,
1422
1429
  indexState,
1423
1430
  breakerCountdown,
1424
1431
  modeLabel,
@@ -1717,6 +1724,18 @@ function StatusBar({
1717
1724
  stateStatusChip,
1718
1725
  fleetWorkingTime != null && fleetWorkingTime > 0 && showChip("elapsed") ? /* @__PURE__ */ jsx5(Text, { dimColor: !isNoColor, children: isNoColor ? fmtElapsed(fleetWorkingTime) : `${STATUSLINE_ICONS.elapsed} ${fmtElapsed(fleetWorkingTime)}` }) : null
1719
1726
  ].filter((c) => c !== null);
1727
+ const showUpdateNotice = Boolean(updateAvailable) && typeof latestVersion === "string" && latestVersion.length > 0 && latestVersion !== version;
1728
+ const versionStatusChip = version ? /* @__PURE__ */ jsxs4(Text, { children: [
1729
+ /* @__PURE__ */ jsxs4(Text, { color: isNoColor ? void 0 : theme.textSecondary, dimColor: !isNoColor, children: [
1730
+ "v",
1731
+ version
1732
+ ] }),
1733
+ showUpdateNotice ? /* @__PURE__ */ jsxs4(Text, { color: isNoColor ? void 0 : STACK_ORANGE, children: [
1734
+ " \xB7 (update v",
1735
+ latestVersion,
1736
+ ")"
1737
+ ] }) : null
1738
+ ] }) : null;
1720
1739
  const minimumChips = [
1721
1740
  // State with animation
1722
1741
  showChip("state") && thinking ? /* @__PURE__ */ jsx5(
@@ -1774,10 +1793,6 @@ function StatusBar({
1774
1793
  ) : null,
1775
1794
  // Fleet working time
1776
1795
  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
1796
  // Work summary (compact)
1782
1797
  ...minimalWorkParts.length > 0 ? [/* @__PURE__ */ jsx5(Text, { dimColor: !isNoColor, children: minimalWorkParts.slice(0, 2).join(" \xB7 ") })] : []
1783
1798
  ].filter((c) => c !== null);
@@ -1846,6 +1861,7 @@ function StatusBar({
1846
1861
  PowerlineRail,
1847
1862
  {
1848
1863
  segments: minimumChips,
1864
+ rightAnchor: versionStatusChip,
1849
1865
  budget: Math.max(12, termWidth),
1850
1866
  monochrome: isNoColor,
1851
1867
  fillBg: LINE_BG_COLORS[0]
@@ -1857,6 +1873,7 @@ function StatusBar({
1857
1873
  PowerlineRail,
1858
1874
  {
1859
1875
  segments: isCompact ? modeChips.slice(0, 5) : modeChips,
1876
+ rightAnchor: versionStatusChip,
1860
1877
  budget: Math.max(12, termWidth),
1861
1878
  monochrome: isNoColor,
1862
1879
  fillBg: LINE_BG_COLORS[0]
@@ -2007,6 +2024,7 @@ function StatusBar({
2007
2024
  children: isNoColor ? `auto in ${autoProceedCountdown}s` : `${STATUSLINE_ICONS.auto_proceed} auto in ${autoProceedCountdown}s`
2008
2025
  }
2009
2026
  ) : null,
2027
+ droppedTools && droppedTools > 0 ? /* @__PURE__ */ jsx5(Text, { color: isNoColor ? void 0 : theme.warn, children: isNoColor ? `-${droppedTools} tools` : `${STATUSLINE_ICONS.tools} -${droppedTools}` }) : null,
2010
2028
  ...detailChips
2011
2029
  ].filter((c) => c !== null),
2012
2030
  budget: Math.max(12, termWidth),
@@ -3639,6 +3657,7 @@ var CONTEXT_MODE_DESCS = {
3639
3657
  deep: "Larger context for complex tasks"
3640
3658
  };
3641
3659
  var STATUSLINE_MODES = ["minimum", "detailed", "no-color"];
3660
+ var DEFAULT_STATUSLINE_MODE = "minimum";
3642
3661
  var REASONING_MODES = ["auto", "on", "off"];
3643
3662
  var REASONING_EFFORTS = [
3644
3663
  "none",
@@ -3651,8 +3670,8 @@ var REASONING_EFFORTS = [
3651
3670
  ];
3652
3671
  var CACHE_TTLS = ["default", "5m", "1h"];
3653
3672
  var STATUSLINE_MODE_DESCS = {
3654
- minimum: "Single line with essential chips only",
3655
- detailed: "Full multi-line statusline (default)",
3673
+ minimum: "Single line with essential chips only (default)",
3674
+ detailed: "Full multi-line statusline",
3656
3675
  "no-color": "Multiline statusline without colors or icons"
3657
3676
  };
3658
3677
  var MAX_ITERATIONS_PRESETS = [100, 200, 500, 1e3, 0];
@@ -4168,7 +4187,7 @@ var SETTINGS_DEFAULTS = Object.freeze({
4168
4187
  enhanceEnabled: true,
4169
4188
  enhanceLanguage: "original",
4170
4189
  debugStream: false,
4171
- statuslineMode: "detailed",
4190
+ statuslineMode: DEFAULT_STATUSLINE_MODE,
4172
4191
  reasoningMode: "auto",
4173
4192
  reasoningEffort: "high",
4174
4193
  reasoningPreserve: false,
@@ -5932,7 +5951,7 @@ var F_KEY_PANEL_ENTRIES = [
5932
5951
  key: 12,
5933
5952
  label: "Kanban board panel",
5934
5953
  action: "toggleKanbanPanel",
5935
- helpKeys: "F12 or Ctrl+J",
5954
+ helpKeys: "F12 or Ctrl+Y",
5936
5955
  helpDescription: "kanban board panel (also /kanban)"
5937
5956
  },
5938
5957
  {
@@ -6213,7 +6232,12 @@ function useAppPickerKeys({
6213
6232
  });
6214
6233
  return;
6215
6234
  }
6216
- dispatch({ type: "replaceHistory", entries: result.entries, nextId: result.nextId });
6235
+ dispatch({
6236
+ type: "replaceHistory",
6237
+ entries: result.entries,
6238
+ nextId: result.nextId,
6239
+ contextSnapshot: result.contextSnapshot
6240
+ });
6217
6241
  dispatch({ type: "resumePickerClose" });
6218
6242
  dispatch({
6219
6243
  type: "addEntry",
@@ -6239,7 +6263,12 @@ function useAppPickerKeys({
6239
6263
  dispatch({ type: "sessionsPanelBusy", on: false });
6240
6264
  return;
6241
6265
  }
6242
- dispatch({ type: "replaceHistory", entries: result.entries, nextId: result.nextId });
6266
+ dispatch({
6267
+ type: "replaceHistory",
6268
+ entries: result.entries,
6269
+ nextId: result.nextId,
6270
+ contextSnapshot: result.contextSnapshot
6271
+ });
6243
6272
  dispatch({ type: "toggleSessionsPanel" });
6244
6273
  dispatch({
6245
6274
  type: "addEntry",
@@ -8588,7 +8617,7 @@ async function handleMemoryWrite(store, sub, rest) {
8588
8617
  try {
8589
8618
  const existing = await Sage.getSage(id);
8590
8619
  if (!existing) return { message: `No memory with id \`${id}\`.` };
8591
- await Sage.deleteSage(id, reason);
8620
+ await Sage.deleteSage(id, reason, { force: true });
8592
8621
  return { message: `Deleted \`${id}\`.` };
8593
8622
  } catch (err) {
8594
8623
  return { message: `Could not delete: ${memErr(err)}` };
@@ -9836,8 +9865,8 @@ function handleCollabDone(event, dispatch, stateRef) {
9836
9865
  // src/hooks/use-file-search.ts
9837
9866
  import * as fs2 from "node:fs/promises";
9838
9867
  import * as path2 from "node:path";
9839
- import { useEffect as useEffect14 } from "react";
9840
9868
  import { toErrorMessage as toErrorMessage4 } from "@wrongstack/core/utils";
9869
+ import { useEffect as useEffect14 } from "react";
9841
9870
 
9842
9871
  // src/file-search.ts
9843
9872
  import * as fs from "node:fs/promises";
@@ -10048,7 +10077,7 @@ var TOKEN_PREVIEWS_MAX_ENTRIES = 64;
10048
10077
  var TOKEN_PREVIEW_MAX_CHARS = 8 * 1024;
10049
10078
  var TOKEN_PREVIEW_MAX_LINES = 6;
10050
10079
  var TOKEN_PREVIEWS_MAX_CHARS = 256 * 1024;
10051
- var TEXT_FILE_ATTACHMENT_MAX_BYTES = 1024 * 1024;
10080
+ var TEXT_FILE_ATTACHMENT_INLINE_MAX_BYTES = 1024 * 1024;
10052
10081
  var TRUNCATION_MARKER = "\u2026 [preview truncated]";
10053
10082
  var ATTACHMENT_WRAPPER_RE = /^<(?:pasted|file(?: path="[^"]*")?)>\n([\s\S]*)\n<\/(?:pasted|file)>$/;
10054
10083
  function createTokenPreview(value, maxChars = TOKEN_PREVIEW_MAX_CHARS, maxLines = TOKEN_PREVIEW_MAX_LINES) {
@@ -10226,17 +10255,13 @@ function useFileSearch(options) {
10226
10255
  const absPath = path2.isAbsolute(picked) ? picked : path2.join(projectRoot, picked);
10227
10256
  try {
10228
10257
  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
- );
10258
+ let data;
10259
+ if (stat3.size > TEXT_FILE_ATTACHMENT_INLINE_MAX_BYTES) {
10260
+ data = fileReadContract(picked, stat3.size);
10261
+ } else {
10262
+ const inline = await fs2.readFile(absPath, "utf8");
10263
+ const bytes = Buffer.byteLength(inline, "utf8");
10264
+ data = bytes > TEXT_FILE_ATTACHMENT_INLINE_MAX_BYTES ? fileReadContract(picked, bytes) : inline;
10240
10265
  }
10241
10266
  const token = await builder.registerFile({
10242
10267
  kind: "file",
@@ -10262,6 +10287,14 @@ function useFileSearch(options) {
10262
10287
  };
10263
10288
  return { onPickerEnter: acceptPickerSelection };
10264
10289
  }
10290
+ function fileReadContract(filePath, bytes) {
10291
+ return [
10292
+ "[File reference contract]",
10293
+ `Referenced project file: ${JSON.stringify(filePath)} (${bytes.toLocaleString()} bytes; content not inlined).`,
10294
+ "Before answering or modifying anything related to this reference, use the available file-reading tools to read the complete file.",
10295
+ "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."
10296
+ ].join("\n");
10297
+ }
10265
10298
 
10266
10299
  // src/hooks/use-help-panel.ts
10267
10300
  import { useCallback as useCallback8 } from "react";
@@ -10541,14 +10574,20 @@ function replaySessionMessages(messages, events, startId) {
10541
10574
  push(ts, { kind: "thinking", text: block.thinking });
10542
10575
  }
10543
10576
  }
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
- );
10577
+ const final = !message.content.some((block) => block.type === "tool_use");
10578
+ const textParts = [];
10579
+ const flushText = () => {
10580
+ const text = textParts.join("").trim();
10581
+ if (text) appendText(message.role, text, ts, final);
10582
+ textParts.length = 0;
10583
+ };
10550
10584
  for (const block of message.content) {
10585
+ if (block.type === "text") {
10586
+ textParts.push(block.text);
10587
+ continue;
10588
+ }
10551
10589
  if (block.type === "tool_use") {
10590
+ flushText();
10552
10591
  const end2 = toolEnds.get(block.id);
10553
10592
  const entry = push(ts, {
10554
10593
  kind: "tool",
@@ -10564,6 +10603,7 @@ function replaySessionMessages(messages, events, startId) {
10564
10603
  continue;
10565
10604
  }
10566
10605
  if (block.type !== "tool_result") continue;
10606
+ flushText();
10567
10607
  const existing = toolEntries.get(block.tool_use_id);
10568
10608
  if (existing) {
10569
10609
  existing.output = toolOutputPreview(block.content);
@@ -10583,6 +10623,7 @@ function replaySessionMessages(messages, events, startId) {
10583
10623
  outputLines: end?.outputLines
10584
10624
  });
10585
10625
  }
10626
+ flushText();
10586
10627
  }
10587
10628
  const dummyPending = /* @__PURE__ */ new Map();
10588
10629
  const dummyCompleted = /* @__PURE__ */ new Map();
@@ -11096,7 +11137,7 @@ function createInitialState(options) {
11096
11137
  enhanceEnabled: true,
11097
11138
  enhanceLanguage: "original",
11098
11139
  debugStream: false,
11099
- statuslineMode: "detailed",
11140
+ statuslineMode: DEFAULT_STATUSLINE_MODE,
11100
11141
  reasoningMode: "auto",
11101
11142
  reasoningEffort: "high",
11102
11143
  reasoningPreserve: false,
@@ -12720,11 +12761,19 @@ function reduceComposer(state, action) {
12720
12761
  const maxBannerId = banners.length > 0 ? Math.max(...banners.map((b) => b.id)) : 0;
12721
12762
  const shifted = action.entries.map((e, i) => ({ ...e, id: maxBannerId + 1 + i }));
12722
12763
  const nextId = maxBannerId + 1 + shifted.length;
12764
+ const snap = action.contextSnapshot;
12765
+ const leaderWithSnap = snap && snap.tokens > 0 ? {
12766
+ ...state.leader,
12767
+ ctxTokens: snap.tokens,
12768
+ ctxMaxTokens: snap.maxContext > 0 ? snap.maxContext : state.leader.ctxMaxTokens
12769
+ } : state.leader;
12723
12770
  return {
12724
12771
  ...state,
12725
12772
  entries: retainTuiHistory([...banners, ...shifted]),
12726
12773
  nextId,
12727
- historyGen: state.historyGen + 1
12774
+ historyGen: state.historyGen + 1,
12775
+ leader: leaderWithSnap,
12776
+ contextChipVersion: state.contextChipVersion + 1
12728
12777
  };
12729
12778
  }
12730
12779
  default:
@@ -13773,7 +13822,7 @@ function reduceSettingsValues(state, action) {
13773
13822
  };
13774
13823
  if (f === 34) {
13775
13824
  const i = STATUSLINE_MODES.indexOf(sp.statuslineMode);
13776
- const base = i < 0 ? STATUSLINE_MODES.indexOf("detailed") : i;
13825
+ const base = i < 0 ? STATUSLINE_MODES.indexOf(DEFAULT_STATUSLINE_MODE) : i;
13777
13826
  const next = (base + action.delta + STATUSLINE_MODES.length) % STATUSLINE_MODES.length;
13778
13827
  return {
13779
13828
  ...state,
@@ -13859,7 +13908,11 @@ function reduceSettingsValues(state, action) {
13859
13908
  if (f === 43)
13860
13909
  return {
13861
13910
  ...state,
13862
- settingsPicker: { ...sp, showSageMemoryInject: !sp.showSageMemoryInject, hint: void 0 }
13911
+ settingsPicker: {
13912
+ ...sp,
13913
+ showSageMemoryInject: !sp.showSageMemoryInject,
13914
+ hint: void 0
13915
+ }
13863
13916
  };
13864
13917
  if (f === 44) {
13865
13918
  const j = SAGE_THRESHOLD_PRESETS.indexOf(sp.sageMemoryInjectThreshold);
@@ -14931,47 +14984,79 @@ import { useEffect as useEffect20, useRef as useRef13, useState as useState7 } f
14931
14984
  import { spawn } from "node:child_process";
14932
14985
  import { buildChildEnv } from "@wrongstack/core/utils";
14933
14986
  async function readGitInfo(cwd) {
14987
+ let added = 0;
14988
+ let deleted = 0;
14989
+ let untracked = 0;
14934
14990
  const [branchRes, numstatRes, statusRes] = await Promise.all([
14935
14991
  runGit(cwd, ["branch", "--show-current"]),
14936
- runGit(cwd, ["diff", "HEAD", "--numstat"]),
14937
- runGit(cwd, ["status", "--porcelain"])
14992
+ foldGit(cwd, ["diff", "HEAD", "--numstat"], (line) => {
14993
+ if (!line) return;
14994
+ const [a, d] = line.split(" ");
14995
+ if (a && a !== "-") added += Number.parseInt(a, 10) || 0;
14996
+ if (d && d !== "-") deleted += Number.parseInt(d, 10) || 0;
14997
+ }),
14998
+ foldGit(cwd, ["status", "--porcelain"], (line) => {
14999
+ if (line.startsWith("?? ")) untracked++;
15000
+ })
14938
15001
  ]);
14939
15002
  if (!branchRes.ok || !numstatRes.ok || !statusRes.ok) return null;
14940
15003
  const branch = branchRes.stdout.trim();
14941
15004
  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
15005
  return { branch: branchLabel, added, deleted, untracked };
14955
15006
  }
14956
15007
  async function detachedShortSha(cwd) {
14957
15008
  const res = await runGit(cwd, ["rev-parse", "--short", "HEAD"]);
14958
15009
  return res.ok ? res.stdout.trim() : null;
14959
15010
  }
15011
+ var MAX_RETAINED_STDOUT = 64 * 1024;
15012
+ var MAX_LINE_CHARS = 64 * 1024;
15013
+ function spawnGit(cwd, args) {
15014
+ return spawn("git", args, {
15015
+ cwd,
15016
+ env: buildChildEnv(),
15017
+ // Inherit stderr (silent) — we don't care about git's noise.
15018
+ stdio: ["ignore", "pipe", "ignore"],
15019
+ // Don't let a slow git hang the TUI.
15020
+ timeout: 3e3,
15021
+ windowsHide: true
15022
+ });
15023
+ }
15024
+ function foldGit(cwd, args, onLine) {
15025
+ return new Promise((resolve) => {
15026
+ try {
15027
+ const child = spawnGit(cwd, args);
15028
+ let carry = "";
15029
+ child.stdout?.setEncoding("utf8");
15030
+ child.stdout?.on("data", (chunk) => {
15031
+ carry += chunk;
15032
+ let start = 0;
15033
+ let nl = carry.indexOf("\n", start);
15034
+ while (nl !== -1) {
15035
+ onLine(carry.slice(start, nl));
15036
+ start = nl + 1;
15037
+ nl = carry.indexOf("\n", start);
15038
+ }
15039
+ if (start > 0) carry = carry.slice(start);
15040
+ if (carry.length > MAX_LINE_CHARS) carry = carry.slice(0, MAX_LINE_CHARS);
15041
+ });
15042
+ child.on("error", () => resolve({ ok: false }));
15043
+ child.on("close", (code) => {
15044
+ if (carry) onLine(carry);
15045
+ resolve({ ok: code === 0 });
15046
+ });
15047
+ } catch {
15048
+ resolve({ ok: false });
15049
+ }
15050
+ });
15051
+ }
14960
15052
  function runGit(cwd, args) {
14961
15053
  return new Promise((resolve) => {
14962
15054
  let stdout = "";
14963
15055
  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) => {
15056
+ const child = spawnGit(cwd, args);
15057
+ child.stdout?.setEncoding("utf8");
15058
+ child.stdout?.on("data", (chunk) => {
15059
+ if (stdout.length >= MAX_RETAINED_STDOUT) return;
14975
15060
  stdout += chunk;
14976
15061
  });
14977
15062
  child.on("error", () => resolve({ ok: false, stdout: "" }));
@@ -15164,7 +15249,7 @@ function useLiveSettingsState({
15164
15249
  confirmExit
15165
15250
  }) {
15166
15251
  const liveSettings = getSettings?.();
15167
- const liveStatuslineMode = liveSettings?.statuslineMode ?? "detailed";
15252
+ const liveStatuslineMode = liveSettings?.statuslineMode ?? DEFAULT_STATUSLINE_MODE;
15168
15253
  const liveAnimationStyle = liveSettings?.animationStyle ?? "rainbow";
15169
15254
  const liveThinkingWord = liveSettings?.thinkingWord ?? "thinking";
15170
15255
  const chimeRef = useRef17(chime);
@@ -15927,7 +16012,7 @@ function usePanelControllers({
15927
16012
  enhanceEnabled: s2.enhanceEnabled ?? true,
15928
16013
  enhanceLanguage: s2.enhanceLanguage ?? "original",
15929
16014
  debugStream: s2.debugStream ?? false,
15930
- statuslineMode: s2.statuslineMode ?? "detailed",
16015
+ statuslineMode: s2.statuslineMode ?? DEFAULT_STATUSLINE_MODE,
15931
16016
  reasoningMode: s2.reasoningMode ?? "auto",
15932
16017
  reasoningEffort: s2.reasoningEffort ?? "high",
15933
16018
  reasoningPreserve: s2.reasoningPreserve ?? false,
@@ -16896,18 +16981,21 @@ function useProviderEventBridge({
16896
16981
  });
16897
16982
  });
16898
16983
  const offMemoryStale = events.on("memory.staled", (e) => {
16984
+ if (!memoryEventMatchesSession(e, agent.ctx.session.id)) return;
16899
16985
  dispatch({
16900
16986
  type: "addEntry",
16901
16987
  entry: { kind: "warn", text: `SAGE stale: ${e.memoryId} \u2014 ${e.reason}` }
16902
16988
  });
16903
16989
  });
16904
16990
  const offMemoryContradicted = events.on("memory.contradicted", (e) => {
16991
+ if (!memoryEventMatchesSession(e, agent.ctx.session.id)) return;
16905
16992
  dispatch({
16906
16993
  type: "addEntry",
16907
16994
  entry: { kind: "warn", text: `SAGE contradicted: ${e.memoryId}` }
16908
16995
  });
16909
16996
  });
16910
16997
  const offMemoryHygiene = events.on("memory.hygiene_completed", (e) => {
16998
+ if (!memoryEventMatchesSession(e, agent.ctx.session.id)) return;
16911
16999
  dispatch({
16912
17000
  type: "addEntry",
16913
17001
  entry: {
@@ -16971,6 +17059,7 @@ function useProviderEventBridge({
16971
17059
  pendingSageStats.clear();
16972
17060
  });
16973
17061
  const offMemoryLifecycle = events.onPattern("memory.*", (event, payload) => {
17062
+ if (!memoryEventMatchesSession(payload, agent.ctx.session.id)) return;
16974
17063
  const lifecycle = memoryLifecycleEntry(event, payload);
16975
17064
  if (!lifecycle) return;
16976
17065
  dispatch({ type: "addEntry", entry: { kind: "memory-lifecycle", ...lifecycle } });
@@ -17795,6 +17884,8 @@ function useStatusbarViewModel({
17795
17884
  clearInterval(id);
17796
17885
  };
17797
17886
  }, [taskPath]);
17887
+ const providerMaxTools = agent.ctx.provider.maxToolsCount ?? 0;
17888
+ const droppedTools = providerMaxTools > 0 ? Math.max(0, (agent.ctx.tools?.length ?? 0) - providerMaxTools) : 0;
17798
17889
  return {
17799
17890
  contextBreakdown,
17800
17891
  currentContextTokens,
@@ -17805,7 +17896,8 @@ function useStatusbarViewModel({
17805
17896
  hasVisibleFleetPanel,
17806
17897
  entriesWithLeader,
17807
17898
  planCounts,
17808
- taskCounts
17899
+ taskCounts,
17900
+ droppedTools
17809
17901
  };
17810
17902
  }
17811
17903
 
@@ -19111,9 +19203,7 @@ import {
19111
19203
  setDesignOverrides
19112
19204
  } from "@wrongstack/core/design";
19113
19205
  import { toErrorMessage as toErrorMessage8 } from "@wrongstack/core/utils";
19114
- import {
19115
- useEffect as useEffect44
19116
- } from "react";
19206
+ import { useEffect as useEffect44 } from "react";
19117
19207
 
19118
19208
  // src/components/autonomy-picker.tsx
19119
19209
  import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
@@ -19278,7 +19368,9 @@ function useTuiSlashCommands({
19278
19368
  motion: pairs["motion"]
19279
19369
  });
19280
19370
  if (Object.keys(patch).length === 0) {
19281
- return { message: 'Usage: /design tune radius=lg density=compact font="\u2026" motion=snappy' };
19371
+ return {
19372
+ message: 'Usage: /design tune radius=lg density=compact font="\u2026" motion=snappy'
19373
+ };
19282
19374
  }
19283
19375
  const merged = await recordOverrides(projectRoot, patch, (/* @__PURE__ */ new Date()).toISOString());
19284
19376
  if (!merged) return { message: "No active kit. Pin one first: /design <kit-id>." };
@@ -19322,7 +19414,13 @@ ${menu}` };
19322
19414
  });
19323
19415
  const fsp = await import("node:fs/promises");
19324
19416
  const nodePath = await import("node:path");
19325
- const abs = nodePath.join(projectRoot, result.path);
19417
+ const { resolveMaterializeTarget } = await import("@wrongstack/core/design");
19418
+ let abs;
19419
+ try {
19420
+ abs = await resolveMaterializeTarget(result.path, projectRoot);
19421
+ } catch (e) {
19422
+ return { message: e.message };
19423
+ }
19326
19424
  try {
19327
19425
  await fsp.mkdir(nodePath.dirname(abs), { recursive: true });
19328
19426
  await fsp.writeFile(abs, result.content);
@@ -22679,7 +22777,7 @@ function KanbanPanel({
22679
22777
  /* @__PURE__ */ jsx24(Text, { dimColor: true, children: "|" }),
22680
22778
  /* @__PURE__ */ jsx24(Text, { children: board.title })
22681
22779
  ] }) : 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" })
22780
+ /* @__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
22781
  ] }),
22684
22782
  prompt ? /* @__PURE__ */ jsx24(PromptLine, { prompt }) : null,
22685
22783
  notice && !prompt ? /* @__PURE__ */ jsx24(Text, { color: "green", wrap: "truncate", children: notice }) : null,
@@ -24789,6 +24887,8 @@ function AppStatusRegion({ host, runtime }) {
24789
24887
  agent,
24790
24888
  agentTranscripts,
24791
24889
  appVersion,
24890
+ latestVersion,
24891
+ updateAvailable,
24792
24892
  director,
24793
24893
  events,
24794
24894
  fleetRoster,
@@ -24858,7 +24958,8 @@ function AppStatusRegion({ host, runtime }) {
24858
24958
  hasVisibleFleetPanel,
24859
24959
  entriesWithLeader,
24860
24960
  planCounts,
24861
- taskCounts
24961
+ taskCounts,
24962
+ droppedTools
24862
24963
  } = statusbar;
24863
24964
  const { mailboxStatus, mailboxPanelOpen, mailboxMessages, mailboxAgents } = mailbox;
24864
24965
  const { lowerFunctionPanelOpen } = viewState;
@@ -24870,6 +24971,8 @@ function AppStatusRegion({ host, runtime }) {
24870
24971
  provider: liveProvider,
24871
24972
  model: liveModel,
24872
24973
  version: appVersion,
24974
+ latestVersion,
24975
+ updateAvailable,
24873
24976
  state: state.status,
24874
24977
  thinkingWord: displayThinkingWord,
24875
24978
  thinkingAnimationStyle: (
@@ -24884,6 +24987,7 @@ function AppStatusRegion({ host, runtime }) {
24884
24987
  queueCount: state.queue.length,
24885
24988
  yolo: yoloLive,
24886
24989
  autonomy: autonomyLive,
24990
+ droppedTools,
24887
24991
  startedAt,
24888
24992
  fleetWorkingTime: fleetWorkingTimeMs,
24889
24993
  todos,
@@ -25269,6 +25373,17 @@ var OAUTH_LABEL = {
25269
25373
  claude: { title: "Claude Pro/Max", detail: "\u2192 anthropic-oauth" },
25270
25374
  copilot: { title: "GitHub Copilot", detail: "\u2192 github-copilot" }
25271
25375
  };
25376
+ function formatExpiry(expiresAt) {
25377
+ if (!expiresAt) return null;
25378
+ const expiry = Date.parse(expiresAt);
25379
+ if (!Number.isFinite(expiry)) return null;
25380
+ const now = Date.now();
25381
+ const msLeft = expiry - now;
25382
+ if (msLeft <= 0) return { text: "expired", color: UI_COLORS.error };
25383
+ if (msLeft < 60 * 6e4) return { text: `${Math.round(msLeft / 6e4)}m left`, color: UI_COLORS.error };
25384
+ if (msLeft < 24 * 60 * 6e4) return { text: `${Math.round(msLeft / (60 * 6e4))}h left`, color: UI_COLORS.warning };
25385
+ return { text: `${Math.round(msLeft / (24 * 60 * 6e4))}d left`, color: UI_COLORS.inactive };
25386
+ }
25272
25387
  function keySummary(keyRow) {
25273
25388
  const method = keyRow.authMethod === "oauth" ? " oauth" : "";
25274
25389
  const created = keyRow.createdAt ? ` ${keyRow.createdAt.slice(0, 10)}` : "";
@@ -25301,6 +25416,7 @@ function renderRow2(row, focused, i) {
25301
25416
  case "key": {
25302
25417
  const k = row.keyRow;
25303
25418
  const badge = badgeForKind(k.authMethod);
25419
+ const expiry = formatExpiry(k.expiresAt);
25304
25420
  return /* @__PURE__ */ jsxs38(Text, { color: rowColor, wrap: "truncate-end", children: [
25305
25421
  marker,
25306
25422
  " ",
@@ -25309,7 +25425,11 @@ function renderRow2(row, focused, i) {
25309
25425
  k.label.padEnd(20),
25310
25426
  " ",
25311
25427
  badge ? /* @__PURE__ */ jsx39(Text, { color: badge.color, children: badge.label.padEnd(8) }) : null,
25312
- /* @__PURE__ */ jsx39(Text, { dimColor: true, children: keySummary(k) })
25428
+ /* @__PURE__ */ jsx39(Text, { dimColor: true, children: keySummary(k) }),
25429
+ expiry ? /* @__PURE__ */ jsxs38(Text, { color: expiry.color, children: [
25430
+ " ",
25431
+ expiry.text
25432
+ ] }) : null
25313
25433
  ] }, `k-${k.label}`);
25314
25434
  }
25315
25435
  case "provider-action":
@@ -26008,7 +26128,7 @@ function ClearConfirmPanel({
26008
26128
  }
26009
26129
 
26010
26130
  // src/components/confirm-prompt.tsx
26011
- import { writeOut as writeOut2 } from "@wrongstack/core/utils";
26131
+ import { unifiedDiff, writeOut as writeOut2 } from "@wrongstack/core/utils";
26012
26132
  import React6 from "react";
26013
26133
 
26014
26134
  // src/highlight.ts
@@ -29020,10 +29140,21 @@ function stringifyInput(input) {
29020
29140
  function truncate2(s2, max) {
29021
29141
  return s2.length <= max ? s2 : `${s2.slice(0, max - 1)}\u2026`;
29022
29142
  }
29023
- function hasDiff(input) {
29024
- return Boolean(
29025
- input && typeof input === "object" && "diff" in input
29026
- );
29143
+ function payloadDiff(input) {
29144
+ if (!input || typeof input !== "object") return "";
29145
+ const obj = input;
29146
+ const filePath = typeof obj["path"] === "string" ? obj["path"] : "file";
29147
+ if (typeof obj["diff"] === "string" && obj["diff"]) return obj["diff"];
29148
+ const newString = obj["new_string"];
29149
+ if (typeof newString === "string") {
29150
+ const oldString = typeof obj["old_string"] === "string" ? obj["old_string"] : "";
29151
+ return unifiedDiff(oldString, newString, { fromFile: filePath, toFile: filePath, context: 2 });
29152
+ }
29153
+ const content = obj["content"];
29154
+ if (typeof content === "string" && content) {
29155
+ return unifiedDiff("", content, { fromFile: "/dev/null", toFile: filePath, context: 0 });
29156
+ }
29157
+ return "";
29027
29158
  }
29028
29159
  var CONFIRM_DIFF_MAX_LINES = 20;
29029
29160
  function renderDiffLine(line) {
@@ -29083,9 +29214,8 @@ function ConfirmPrompt({
29083
29214
  }
29084
29215
  });
29085
29216
  const inputSummary = stringifyInput(input);
29086
- const showDiff = hasDiff(input);
29087
29217
  const inp = input;
29088
- const diff = typeof inp?.diff === "string" ? inp.diff : "";
29218
+ const diff = payloadDiff(input);
29089
29219
  const diffPath = typeof inp?.path === "string" ? inp.path : void 0;
29090
29220
  return /* @__PURE__ */ jsxs46(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
29091
29221
  /* @__PURE__ */ jsxs46(Box, { flexDirection: "row", children: [
@@ -29098,7 +29228,7 @@ function ConfirmPrompt({
29098
29228
  "KANBAN BOUNDARY: ",
29099
29229
  boundaryReason
29100
29230
  ] }) : null,
29101
- showDiff && diff ? /* @__PURE__ */ jsx47(Box, { flexDirection: "column", marginY: 1, children: renderDiff(diff, diffPath) }) : null,
29231
+ diff ? /* @__PURE__ */ jsx47(Box, { flexDirection: "column", marginY: 1, children: renderDiff(diff, diffPath) }) : null,
29102
29232
  /* @__PURE__ */ jsx47(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
29103
29233
  /* @__PURE__ */ jsx47(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx47(Text, { children: buttonLabels(suggestedPattern).map((l) => /* @__PURE__ */ jsxs46(React6.Fragment, { children: [
29104
29234
  /* @__PURE__ */ jsx47(Text, { bold: true, color: BUTTON_COLOR[l.decision], children: l.bracket }),
@@ -32221,6 +32351,39 @@ function parseInline(text) {
32221
32351
  continue;
32222
32352
  }
32223
32353
  }
32354
+ if (ch === "[") {
32355
+ const textEnd = text.indexOf("]", i + 1);
32356
+ if (textEnd > i && text[textEnd + 1] === "(") {
32357
+ const urlEnd = text.indexOf(")", textEnd + 2);
32358
+ if (urlEnd > textEnd) {
32359
+ flush();
32360
+ const linkText = text.slice(i + 1, textEnd);
32361
+ tokens.push({ text: linkText, link: true });
32362
+ i = urlEnd + 1;
32363
+ continue;
32364
+ }
32365
+ }
32366
+ }
32367
+ if (text.startsWith("http://", i) || text.startsWith("https://", i)) {
32368
+ let urlEnd = i + 8;
32369
+ while (urlEnd < text.length) {
32370
+ const c = text[urlEnd];
32371
+ if (c !== void 0 && c.match(/[a-zA-Z0-9._~:/?#@!$&+,;=%\-\[\]()'*]/)) {
32372
+ urlEnd++;
32373
+ } else {
32374
+ break;
32375
+ }
32376
+ }
32377
+ const trailing = text.slice(i, urlEnd);
32378
+ const stripped = trailing.replace(/[.,;!?)]+$/, "");
32379
+ urlEnd = i + stripped.length;
32380
+ if (urlEnd > i + 8) {
32381
+ flush();
32382
+ tokens.push({ text: stripped, link: true });
32383
+ i = urlEnd;
32384
+ continue;
32385
+ }
32386
+ }
32224
32387
  plain += ch;
32225
32388
  i += 1;
32226
32389
  }
@@ -32238,7 +32401,7 @@ function InlineLine({ tokens, dim }) {
32238
32401
  return /* @__PURE__ */ jsx66(Text, { children: tokens.map((t, j) => /* @__PURE__ */ jsx66(
32239
32402
  Text,
32240
32403
  {
32241
- color: t.code ? theme.accent : "white",
32404
+ color: t.code ? theme.accent : t.link ? theme.accent : "white",
32242
32405
  bold: Boolean(t.bold),
32243
32406
  italic: Boolean(t.italic),
32244
32407
  strikethrough: Boolean(t.strike),
@@ -32395,7 +32558,7 @@ var ASSISTANT_TAIL_HEIGHT = ASSISTANT_TAIL_MARGIN_Y + ASSISTANT_TAIL_HEADER_ROWS
32395
32558
 
32396
32559
  // src/components/history/banner.tsx
32397
32560
  import { Fragment as Fragment22, jsx as jsx68, jsxs as jsxs66 } from "react/jsx-runtime";
32398
- var STACK_ORANGE = "#FD9F02";
32561
+ var STACK_ORANGE2 = "#FD9F02";
32399
32562
  var SIGNAL_PINK = "#FE2E5F";
32400
32563
  var BORDER = "#3B3C36";
32401
32564
  var MUTED = "#B6B2A8";
@@ -32429,7 +32592,7 @@ function BrandMark({ pinkRow = 1 }) {
32429
32592
  if (column === PINK_HOME && (row === pinkRow || row === pinkRow + 1)) {
32430
32593
  return SIGNAL_PINK;
32431
32594
  }
32432
- if (row < 2 && column !== PINK_HOME) return STACK_ORANGE;
32595
+ if (row < 2 && column !== PINK_HOME) return STACK_ORANGE2;
32433
32596
  return null;
32434
32597
  })
32435
32598
  );
@@ -32480,7 +32643,7 @@ var WORDMARK_LINES = Object.freeze(
32480
32643
  );
32481
32644
  function bannerGradientColor(position, length) {
32482
32645
  const progress = length > 1 ? position / (length - 1) : 0.5;
32483
- return mixHex(STACK_ORANGE, SIGNAL_PINK, progress);
32646
+ return mixHex(STACK_ORANGE2, SIGNAL_PINK, progress);
32484
32647
  }
32485
32648
  function GradientText({ text }) {
32486
32649
  return /* @__PURE__ */ jsx68(Text, { bold: true, children: [...text].map(
@@ -32505,7 +32668,7 @@ function InfoRow({
32505
32668
  }) {
32506
32669
  const labelWidth = compact ? 6 : 9;
32507
32670
  const valueWidth = Math.max(1, contentWidth - labelWidth - 3);
32508
- const color = accent ? STACK_ORANGE : MUTED;
32671
+ const color = accent ? STACK_ORANGE2 : MUTED;
32509
32672
  return /* @__PURE__ */ jsxs66(Text, { children: [
32510
32673
  /* @__PURE__ */ jsx68(Text, { color, children: icon }),
32511
32674
  /* @__PURE__ */ jsx68(Text, { color, bold: true, children: ` ${trunc(label, labelWidth).padEnd(labelWidth)} ` }),
@@ -32542,11 +32705,11 @@ function ProfileRow({
32542
32705
  const profileSegment = segmentMatch?.[1] ?? "";
32543
32706
  const segIdx = profileSegment ? displayPath.lastIndexOf(profileSegment) : -1;
32544
32707
  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)} ` }),
32708
+ /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE2, children: icon }),
32709
+ /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE2, bold: true, children: ` ${trunc(label, labelWidth).padEnd(labelWidth)} ` }),
32547
32710
  segIdx >= 0 && profileSegment ? /* @__PURE__ */ jsxs66(Fragment22, { children: [
32548
32711
  /* @__PURE__ */ jsx68(Text, { color: MUTED, children: displayPath.slice(0, segIdx) }),
32549
- /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE, bold: true, children: profileSegment }),
32712
+ /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE2, bold: true, children: profileSegment }),
32550
32713
  /* @__PURE__ */ jsx68(Text, { color: MUTED, children: displayPath.slice(segIdx + profileSegment.length) })
32551
32714
  ] }) : /* @__PURE__ */ jsx68(Text, { color: MUTED, children: displayPath })
32552
32715
  ] });
@@ -32559,7 +32722,7 @@ function Footer({ contentWidth, compact }) {
32559
32722
  /* @__PURE__ */ jsx68(Text, { dimColor: true, children: OSC8_WRONGSTACK }),
32560
32723
  !compact || contentWidth >= 35 ? /* @__PURE__ */ jsxs66(Fragment22, { children: [
32561
32724
  /* @__PURE__ */ jsx68(Text, { dimColor: true, children: " \xB7 " }),
32562
- /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE, children: "\u2605 " }),
32725
+ /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE2, children: "\u2605 " }),
32563
32726
  /* @__PURE__ */ jsx68(Text, { dimColor: true, children: OSC8_GITHUB })
32564
32727
  ] }) : null
32565
32728
  ] }) });
@@ -32585,7 +32748,7 @@ function AutonomyAgentsSection({
32585
32748
  if (!agent) return null;
32586
32749
  const online = agent.online;
32587
32750
  const indicator = online ? "\u25CF" : "\xB7";
32588
- const color = online ? STACK_ORANGE : MUTED;
32751
+ const color = online ? STACK_ORANGE2 : MUTED;
32589
32752
  const detail = agent.detail;
32590
32753
  return /* @__PURE__ */ jsxs66(Box, { flexDirection: "row", marginRight: 2, children: [
32591
32754
  /* @__PURE__ */ jsx68(Text, { color, children: indicator }),
@@ -32632,9 +32795,9 @@ function Banner({
32632
32795
  Math.max(1, panelWidth - (unbordered ? 0 : 4))
32633
32796
  );
32634
32797
  if (unbordered) {
32635
- return /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE, bold: true, children: summary });
32798
+ return /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE2, bold: true, children: summary });
32636
32799
  }
32637
- return /* @__PURE__ */ jsx68(Box, { width: panelWidth, borderStyle: "round", borderColor: BORDER, paddingX: 1, children: /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE, bold: true, children: summary }) });
32800
+ return /* @__PURE__ */ jsx68(Box, { width: panelWidth, borderStyle: "round", borderColor: BORDER, paddingX: 1, children: /* @__PURE__ */ jsx68(Text, { color: STACK_ORANGE2, bold: true, children: summary }) });
32638
32801
  }
32639
32802
  return /* @__PURE__ */ jsxs66(
32640
32803
  Box,
@@ -32651,7 +32814,7 @@ function Banner({
32651
32814
  "v",
32652
32815
  version
32653
32816
  ] }),
32654
- entry.updateAvailable && entry.latestVersion ? /* @__PURE__ */ jsxs66(Text, { color: STACK_ORANGE, children: [
32817
+ entry.updateAvailable && entry.latestVersion ? /* @__PURE__ */ jsxs66(Text, { color: STACK_ORANGE2, children: [
32655
32818
  " \xB7 (update available: v",
32656
32819
  entry.latestVersion,
32657
32820
  ")"
@@ -33600,6 +33763,7 @@ var History = memo2(function History2({
33600
33763
  // src/components/scrollable-history.tsx
33601
33764
  import { jsx as jsx72, jsxs as jsxs70 } from "react/jsx-runtime";
33602
33765
  var LIVE_TOOL_STREAM_COPY_ID = -1;
33766
+ var SELECTION_COPY_ID = -2;
33603
33767
  function findCopyHit(hits, row, col) {
33604
33768
  for (let i = hits.length - 1; i >= 0; i--) {
33605
33769
  const hit = hits[i];
@@ -33629,7 +33793,8 @@ function copyRegistryVisibleClip(opts) {
33629
33793
  return Math.max(0, opts.mountedRows + opts.tailRows - opts.viewportRows);
33630
33794
  }
33631
33795
  function liveToolStreamCopyHit(opts) {
33632
- const headerRow = opts.mountedRows - opts.visibleClip + 1;
33796
+ const slack = opts.pinnedSlack ?? 0;
33797
+ const headerRow = opts.mountedRows - opts.visibleClip + 1 + slack;
33633
33798
  if (!opts.visible || headerRow < 0 || headerRow >= opts.viewportRows) return null;
33634
33799
  return {
33635
33800
  entryId: LIVE_TOOL_STREAM_COPY_ID,
@@ -33638,6 +33803,36 @@ function liveToolStreamCopyHit(opts) {
33638
33803
  iconCol: opts.iconCol
33639
33804
  };
33640
33805
  }
33806
+ function normalizeSelection(a, b, inProgress) {
33807
+ const topLeft = { row: Math.min(a.row, b.row), col: Math.min(a.col, b.col) };
33808
+ const bottomRight = { row: Math.max(a.row, b.row), col: Math.max(a.col, b.col) };
33809
+ return { topLeft, bottomRight, inProgress };
33810
+ }
33811
+ function isOutOfBand(col, termWidth) {
33812
+ return col < 0 || col >= termWidth;
33813
+ }
33814
+ function selectionToSlices(opts) {
33815
+ const { selection, cards, cardVisibleCols } = opts;
33816
+ const maxCol = Math.max(0, cardVisibleCols - 1);
33817
+ const result = [];
33818
+ for (const card of cards) {
33819
+ const visTop = Math.max(selection.topLeft.row, card.viewportStartRow);
33820
+ const visBot = Math.min(selection.bottomRight.row, card.viewportEndRow - 1);
33821
+ if (visTop > visBot) continue;
33822
+ const entryStartRow = visTop - card.viewportStartRow;
33823
+ const entryEndRow = visBot - card.viewportStartRow;
33824
+ const startCol = entryStartRow === selection.topLeft.row - card.viewportStartRow ? Math.max(0, Math.min(maxCol, selection.topLeft.col)) : 0;
33825
+ const endCol = entryEndRow === selection.bottomRight.row - card.viewportStartRow ? Math.max(startCol, Math.min(maxCol, selection.bottomRight.col)) : maxCol;
33826
+ result.push({
33827
+ entryId: card.entryId,
33828
+ startRow: entryStartRow,
33829
+ startCol,
33830
+ endRow: entryEndRow,
33831
+ endCol
33832
+ });
33833
+ }
33834
+ return result;
33835
+ }
33641
33836
  function buildCopyRegistry(opts) {
33642
33837
  const mountedGroupRows = opts.renderGroups.reduce(
33643
33838
  (rows, group) => rows + (opts.heightCache.getHeight(renderGroupId(group)) ?? 0),
@@ -33650,12 +33845,13 @@ function buildCopyRegistry(opts) {
33650
33845
  tailRows: opts.tailRows,
33651
33846
  viewportRows: opts.viewportRows
33652
33847
  });
33848
+ const pinnedSlack = !opts.scrolled ? Math.max(0, opts.viewportRows - mountedGroupRows - opts.tailRows) : 0;
33653
33849
  const hits = [];
33654
33850
  let offset = 0;
33655
33851
  for (const group of opts.renderGroups) {
33656
33852
  const gid = renderGroupId(group);
33657
33853
  const groupHeight = opts.heightCache.getHeight(gid) ?? 0;
33658
- const startRow = offset - visibleClip;
33854
+ const startRow = offset - visibleClip + pinnedSlack;
33659
33855
  offset += groupHeight;
33660
33856
  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
33857
  const entryId = groupEntryIds[0];
@@ -33675,7 +33871,8 @@ function buildCopyRegistry(opts) {
33675
33871
  mountedRows: mountedGroupRows,
33676
33872
  visibleClip,
33677
33873
  viewportRows: opts.viewportRows,
33678
- iconCol: opts.iconCol
33874
+ iconCol: opts.iconCol,
33875
+ pinnedSlack
33679
33876
  })
33680
33877
  };
33681
33878
  }
@@ -33691,6 +33888,100 @@ function scrollbarThumb(rows, offset, total) {
33691
33888
  );
33692
33889
  return { top, size, scrollable: true };
33693
33890
  }
33891
+ function buildMountedCardSpans(opts) {
33892
+ const mountedGroupRows = opts.renderGroups.reduce(
33893
+ (rows, group) => rows + (opts.heightCache.getHeight(renderGroupId(group)) ?? 0),
33894
+ 0
33895
+ );
33896
+ const visibleClip = copyRegistryVisibleClip({
33897
+ scrolled: opts.scrolled,
33898
+ clip: opts.clip,
33899
+ mountedRows: mountedGroupRows,
33900
+ tailRows: opts.tailRows,
33901
+ viewportRows: opts.viewportRows
33902
+ });
33903
+ const spans = [];
33904
+ let offset = 0;
33905
+ const pinnedSlack = !opts.scrolled ? Math.max(0, opts.viewportRows - mountedGroupRows - opts.tailRows) : 0;
33906
+ for (const group of opts.renderGroups) {
33907
+ const gid = renderGroupId(group);
33908
+ const groupHeight = opts.heightCache.getHeight(gid) ?? 0;
33909
+ const viewportStartRow = offset - visibleClip + pinnedSlack;
33910
+ offset += groupHeight;
33911
+ 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] : [];
33912
+ const entryId = entryIds[0];
33913
+ if (entryId === void 0) continue;
33914
+ const viewportEndRow = viewportStartRow + groupHeight;
33915
+ if (viewportEndRow <= 0 || viewportStartRow >= opts.viewportRows) continue;
33916
+ spans.push({
33917
+ entryId,
33918
+ viewportStartRow,
33919
+ viewportEndRow,
33920
+ totalRows: groupHeight,
33921
+ ...entryIds.length > 1 ? { entryIds } : {}
33922
+ });
33923
+ }
33924
+ return spans;
33925
+ }
33926
+ function selectionHitAt(row, spans) {
33927
+ for (const span of spans) {
33928
+ if (row >= span.viewportStartRow && row < span.viewportEndRow) {
33929
+ return { entryId: span.entryId, ...span.entryIds ? { entryIds: span.entryIds } : {} };
33930
+ }
33931
+ }
33932
+ return null;
33933
+ }
33934
+ function assembleSelectionText(opts) {
33935
+ const { slices, entriesById, toolGroupsByHeadId } = opts;
33936
+ if (slices.length === 0) return "";
33937
+ const byEntry = /* @__PURE__ */ new Map();
33938
+ for (const slice of slices) {
33939
+ const list = byEntry.get(slice.entryId);
33940
+ if (list) list.push(slice);
33941
+ else byEntry.set(slice.entryId, [slice]);
33942
+ }
33943
+ const segments = [];
33944
+ let toolGroupCount = 0;
33945
+ for (const [entryId, entrySlices] of byEntry) {
33946
+ const head = entriesById.get(entryId);
33947
+ if (!head) continue;
33948
+ const groupMembers = toolGroupsByHeadId?.get(entryId);
33949
+ const entries = groupMembers && groupMembers.length > 1 ? groupMembers.map((id) => entriesById.get(id)).filter((entry) => entry !== void 0) : [head];
33950
+ if (entries.length === 0) continue;
33951
+ if (entries.length > 1) toolGroupCount += 1;
33952
+ const fullText = entries.length === 1 ? copyableTextForEntry(entries[0]) : copyableTextForEntries(entries);
33953
+ if (fullText.length === 0) continue;
33954
+ if (entries.length > 1) {
33955
+ segments.push(fullText);
33956
+ continue;
33957
+ }
33958
+ for (const slice of entrySlices) {
33959
+ const rows = fullText.split("\n");
33960
+ const collected = [];
33961
+ for (let r = slice.startRow; r <= slice.endRow && r < rows.length; r++) {
33962
+ const line = rows[r] ?? "";
33963
+ if (slice.startRow === slice.endRow) {
33964
+ const start = Math.max(0, Math.min(line.length, slice.startCol));
33965
+ const end = Math.max(start, Math.min(line.length, slice.endCol + 1));
33966
+ if (end > start) collected.push(line.slice(start, end));
33967
+ } else if (r === slice.startRow) {
33968
+ const start = Math.max(0, Math.min(line.length, slice.startCol));
33969
+ if (start < line.length) collected.push(line.slice(start));
33970
+ } else if (r === slice.endRow) {
33971
+ const end = Math.max(0, Math.min(line.length, slice.endCol + 1));
33972
+ if (end > 0) collected.push(line.slice(0, end));
33973
+ } else {
33974
+ collected.push(line);
33975
+ }
33976
+ }
33977
+ const seg = collected.join("\n");
33978
+ if (seg.length > 0) segments.push(seg);
33979
+ }
33980
+ }
33981
+ if (segments.length === 0) return "";
33982
+ const separator = byEntry.size > 1 || toolGroupCount > 0 ? "\n---\n" : "\n";
33983
+ return segments.join(separator);
33984
+ }
33694
33985
  function Scrollbar({
33695
33986
  rows,
33696
33987
  offset,
@@ -33776,6 +34067,9 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
33776
34067
  const measuredGroupIdsRef = useRef37(/* @__PURE__ */ new Set());
33777
34068
  const copyHitsRef = useRef37([]);
33778
34069
  const liveToolCopyHitRef = useRef37(null);
34070
+ const mountedGroupSpansRef = useRef37([]);
34071
+ const spansSignatureRef = useRef37("");
34072
+ const selectionRef = useRef37({ anchor: null, head: null, inProgress: false });
33779
34073
  const toolStreamRef = useRef37(toolStream);
33780
34074
  toolStreamRef.current = toolStream;
33781
34075
  const entriesByIdRef = useRef37(/* @__PURE__ */ new Map());
@@ -33891,6 +34185,7 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
33891
34185
  const ids = groupIdsRef.current;
33892
34186
  const nextId = next ? ids[next.index] : void 0;
33893
34187
  const normalized = next && nextId !== void 0 ? { index: next.index, clip: Math.max(0, next.clip) } : null;
34188
+ selectionRef.current = { anchor: null, head: null, inProgress: false };
33894
34189
  effectiveAnchorRef.current = normalized;
33895
34190
  setAnchor(normalized && nextId !== void 0 ? { id: nextId, clip: normalized.clip } : null);
33896
34191
  setMountBump(0);
@@ -33936,9 +34231,77 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
33936
34231
  );
33937
34232
  if (payload === null) return null;
33938
34233
  return await writeClipboardText(payload.text) ? payload.entryId : null;
34234
+ },
34235
+ beginSelection: (row, col) => {
34236
+ if (isOutOfBand(col, termWidth)) {
34237
+ selectionRef.current = { anchor: null, head: null, inProgress: false };
34238
+ return;
34239
+ }
34240
+ const cardHit = selectionHitAt(row, mountedGroupSpansRef.current);
34241
+ if (cardHit === null) {
34242
+ selectionRef.current = { anchor: null, head: null, inProgress: false };
34243
+ return;
34244
+ }
34245
+ selectionRef.current = {
34246
+ anchor: { row, col },
34247
+ head: { row, col },
34248
+ inProgress: true
34249
+ };
34250
+ },
34251
+ extendSelection: (row, col) => {
34252
+ const cur = selectionRef.current;
34253
+ if (cur.anchor === null) return;
34254
+ if (cur.inProgress === false) return;
34255
+ if (isOutOfBand(col, termWidth) || row < 0 || row >= vp) {
34256
+ selectionRef.current = { anchor: null, head: null, inProgress: false };
34257
+ return;
34258
+ }
34259
+ selectionRef.current = { ...cur, head: { row, col } };
34260
+ },
34261
+ endSelection: () => {
34262
+ const cur = selectionRef.current;
34263
+ if (cur.anchor === null) return;
34264
+ selectionRef.current = { ...cur, inProgress: false };
34265
+ },
34266
+ clearSelection: () => {
34267
+ const cur = selectionRef.current;
34268
+ if (cur.anchor === null && cur.head === null) return;
34269
+ selectionRef.current = { anchor: null, head: null, inProgress: false };
34270
+ },
34271
+ commitSelection: async () => {
34272
+ const cur = selectionRef.current;
34273
+ if (cur.anchor === null || cur.head === null) return false;
34274
+ if (cur.anchor.row === cur.head.row && cur.anchor.col === cur.head.col) {
34275
+ selectionRef.current = { anchor: null, head: null, inProgress: false };
34276
+ return false;
34277
+ }
34278
+ const rect = normalizeSelection(cur.anchor, cur.head, cur.inProgress);
34279
+ const slices = selectionToSlices({
34280
+ selection: rect,
34281
+ cards: mountedGroupSpansRef.current,
34282
+ cardVisibleCols: termWidth
34283
+ });
34284
+ const toolGroupsByHeadId = /* @__PURE__ */ new Map();
34285
+ for (const span of mountedGroupSpansRef.current) {
34286
+ if (span.entryIds && span.entryIds.length > 1) {
34287
+ toolGroupsByHeadId.set(span.entryId, span.entryIds);
34288
+ }
34289
+ }
34290
+ const text = assembleSelectionText({
34291
+ slices,
34292
+ entriesById: entriesByIdRef.current,
34293
+ ...toolGroupsByHeadId.size > 0 ? { toolGroupsByHeadId } : {}
34294
+ });
34295
+ selectionRef.current = { anchor: null, head: null, inProgress: false };
34296
+ if (text.length === 0) return false;
34297
+ try {
34298
+ return await writeClipboardText(text);
34299
+ } catch {
34300
+ return false;
34301
+ }
33939
34302
  }
33940
34303
  }),
33941
- [applyAnchor]
34304
+ [applyAnchor, termWidth, vp]
33942
34305
  );
33943
34306
  useEffect67(() => {
33944
34307
  if (!controllerRef) return void 0;
@@ -33993,6 +34356,23 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
33993
34356
  copyHitsRef.current = copyRegistry.hits;
33994
34357
  liveToolCopyHitRef.current = copyRegistry.liveHit;
33995
34358
  const copyRailHits = copyRegistry.liveHit ? [...copyRegistry.hits, copyRegistry.liveHit] : copyRegistry.hits;
34359
+ const nextSpans = buildMountedCardSpans({
34360
+ renderGroups,
34361
+ heightCache,
34362
+ scrolled,
34363
+ clip: clip2,
34364
+ tailRows: plan.mountTail ? toolTailHeight : 0,
34365
+ viewportRows: vp,
34366
+ showModelReasoning
34367
+ });
34368
+ const nextSignature = nextSpans.map((s2) => `${s2.entryId}:${s2.viewportStartRow}:${s2.viewportEndRow}`).join("|");
34369
+ if (nextSignature !== spansSignatureRef.current) {
34370
+ if (selectionRef.current.anchor !== null && !selectionRef.current.inProgress) {
34371
+ selectionRef.current = { anchor: null, head: null, inProgress: false };
34372
+ }
34373
+ spansSignatureRef.current = nextSignature;
34374
+ }
34375
+ mountedGroupSpansRef.current = nextSpans;
33996
34376
  useLayoutEffect2(() => {
33997
34377
  let changed = false;
33998
34378
  for (const group of renderGroups) {
@@ -34057,6 +34437,8 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
34057
34437
  }
34058
34438
  if (planStartIdxRef.current > 0) {
34059
34439
  requestOlderFiredRef.current = false;
34440
+ } else if (!scrolled) {
34441
+ requestOlderFiredRef.current = false;
34060
34442
  }
34061
34443
  if (changed) setMeasureTick((tick) => tick + 1);
34062
34444
  });
@@ -36461,7 +36843,7 @@ function routeSettingsOverlayKey(host, input, key, isEnter) {
36461
36843
  enhanceEnabled: config.enhanceEnabled ?? true,
36462
36844
  enhanceLanguage: config.enhanceLanguage ?? "original",
36463
36845
  debugStream: config.debugStream ?? false,
36464
- statuslineMode: config.statuslineMode ?? "detailed",
36846
+ statuslineMode: config.statuslineMode ?? DEFAULT_STATUSLINE_MODE,
36465
36847
  reasoningMode: config.reasoningMode ?? "auto",
36466
36848
  reasoningEffort: config.reasoningEffort ?? "high",
36467
36849
  reasoningPreserve: config.reasoningPreserve ?? false,
@@ -36738,7 +37120,7 @@ function createAppKeyHandler(options) {
36738
37120
  dispatch({ type: "toggleSddBoardMonitor" });
36739
37121
  return;
36740
37122
  }
36741
- if (key.ctrl && input === "j") {
37123
+ if (key.ctrl && input === "y") {
36742
37124
  dispatch({ type: "toggleKanbanPanel" });
36743
37125
  return;
36744
37126
  }
@@ -36778,7 +37160,7 @@ function createAppKeyHandler(options) {
36778
37160
  }
36779
37161
  }
36780
37162
  }
36781
- if (state.sddBoard?.monitorOpen && !key.ctrl && !key.meta) {
37163
+ if (state.sddBoard?.monitorOpen && !key.ctrl && !key.meta && draftRef.current.buffer === "") {
36782
37164
  if (key.rightArrow) {
36783
37165
  dispatch({ type: "sddBoardFocusNext" });
36784
37166
  return;
@@ -36839,6 +37221,20 @@ function createAppKeyHandler(options) {
36839
37221
  return;
36840
37222
  }
36841
37223
  if (!overlayOpen) {
37224
+ if (mouseMode && key.mouse?.kind === "press" && key.mouse.button === "right") {
37225
+ const region = hitRegion(
37226
+ { termRows, termCols: stdout?.columns ?? 80, viewportRows: state.viewportRows },
37227
+ key.mouse.x,
37228
+ key.mouse.y
37229
+ );
37230
+ if (region?.kind === "history" && key.mouse.x <= (stdout?.columns ?? 80) - SCROLLBAR_HIT_WIDTH) {
37231
+ void historyScrollRef.current?.commitSelection().then((copied) => {
37232
+ if (copied) onHistoryCopy?.(SELECTION_COPY_ID);
37233
+ });
37234
+ return;
37235
+ }
37236
+ historyScrollRef.current?.clearSelection();
37237
+ }
36842
37238
  if (key.mouse?.kind === "wheel" && key.mouse.wheel !== 0) {
36843
37239
  if (isHistoryScrollTarget(
36844
37240
  { termRows, termCols: stdout?.columns ?? 80, viewportRows: state.viewportRows },
@@ -36848,6 +37244,7 @@ function createAppKeyHandler(options) {
36848
37244
  if (key.mouse.shift)
36849
37245
  historyScrollRef.current?.scrollPage(key.mouse.wheel > 0 ? "up" : "down");
36850
37246
  else historyScrollRef.current?.scrollBy(key.mouse.wheel > 0 ? 1 : -1);
37247
+ historyScrollRef.current?.clearSelection();
36851
37248
  return;
36852
37249
  }
36853
37250
  }
@@ -36859,16 +37256,31 @@ function createAppKeyHandler(options) {
36859
37256
  );
36860
37257
  const copyRow = region?.kind === "history" ? region.row : region?.kind === "scrollbar" ? region.cell : null;
36861
37258
  if (copyRow !== null && key.mouse.kind === "press" && historyScrollRef.current?.hasCopyTargetAt(copyRow, key.mouse.x - 1)) {
37259
+ historyScrollRef.current?.clearSelection();
36862
37260
  void historyScrollRef.current.copyAtViewportCell(copyRow, key.mouse.x - 1).then((entryId) => {
36863
37261
  if (entryId !== null) onHistoryCopy?.(entryId);
36864
37262
  }).catch(() => null);
36865
37263
  return;
36866
37264
  }
37265
+ if (mouseMode && region?.kind === "history" && key.mouse.x <= (stdout?.columns ?? 80) - SCROLLBAR_HIT_WIDTH) {
37266
+ if (key.mouse.kind === "press") {
37267
+ historyScrollRef.current?.beginSelection(region.row, key.mouse.x - 1);
37268
+ return;
37269
+ }
37270
+ if (key.mouse.kind === "move") {
37271
+ historyScrollRef.current?.extendSelection(region.row, key.mouse.x - 1);
37272
+ return;
37273
+ }
37274
+ }
36867
37275
  if (region?.kind === "scrollbar") {
37276
+ historyScrollRef.current?.clearSelection();
36868
37277
  historyScrollRef.current?.scrollToTrackCell(region.cell);
36869
37278
  return;
36870
37279
  }
36871
37280
  }
37281
+ if (mouseMode && key.mouse?.kind === "release" && key.mouse.button === "left") {
37282
+ historyScrollRef.current?.endSelection();
37283
+ }
36872
37284
  if (mouseMode && key.mouse?.kind === "press" && key.mouse.button === "left" && statusBarWrapRef.current) {
36873
37285
  const sbHeight = measureElement(statusBarWrapRef.current).height;
36874
37286
  const belowHeight = belowStatusBarRef.current ? measureElement(belowStatusBarRef.current).height : 0;
@@ -38343,6 +38755,7 @@ var origConsoleInfo = console.info;
38343
38755
  var origConsoleTable = console.table;
38344
38756
  var origConsoleTrace = console.trace;
38345
38757
  var origStderrWrite = process.stderr.write.bind(process.stderr);
38758
+ var origStdoutWrite = process.stdout.write.bind(process.stdout);
38346
38759
  var consoleNoop = (..._args) => {
38347
38760
  };
38348
38761
  var stderrNoop = ((_chunk, _encodingOrCb, _cb) => {
@@ -38372,6 +38785,7 @@ function unsilenceTerminal() {
38372
38785
  console.table = origConsoleTable;
38373
38786
  console.trace = origConsoleTrace;
38374
38787
  process.stderr.write = origStderrWrite;
38788
+ process.stdout.write = origStdoutWrite;
38375
38789
  process.off("warning", warningNoop);
38376
38790
  }
38377
38791
 
@@ -38389,6 +38803,10 @@ async function runTui(opts) {
38389
38803
  const capability = detectTerminal({ stdin, stdout });
38390
38804
  const mouseEnabled = opts.mouse ?? opts.getSettings?.().mouseMode ?? process.env.WRONGSTACK_MOUSE === "1";
38391
38805
  silenceTerminal();
38806
+ const provider = opts.agent.ctx.provider;
38807
+ if (provider?.suppressMaxToolsWarning) {
38808
+ provider.suppressMaxToolsWarning();
38809
+ }
38392
38810
  const inkStdin = stdin;
38393
38811
  const {
38394
38812
  controller: titleController,