@deepseek-harness-tui/dsh-tui 0.8.8 → 0.9.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 (467) hide show
  1. package/README.md +60 -238
  2. package/bin/dsh-tui.js +172 -5
  3. package/cordis.patch.yml +16 -4
  4. package/dsh-ecosystem-spec/protocols/profile-definitions.d.ts +13 -13
  5. package/dsh-ecosystem-spec/protocols/profile-definitions.js +59 -59
  6. package/dsh-ecosystem-spec/protocols/tui-channel-http.d.ts +15 -15
  7. package/dsh-ecosystem-spec/protocols/tui-channel-http.js +32 -32
  8. package/dsh-ecosystem-spec/protocols/tui-channel.d.ts +59 -59
  9. package/dsh-ecosystem-spec/protocols/tui-channel.js +166 -166
  10. package/dsh-ecosystem-spec/protocols/tui-contributions.d.ts +42 -42
  11. package/dsh-ecosystem-spec/protocols/tui-contributions.js +143 -143
  12. package/dsh-ecosystem-spec/registry/README.md +14 -14
  13. package/dsh-ecosystem-spec/registry/host-descriptor.tui.example.json +56 -56
  14. package/dsh-ecosystem-spec/registry/permissions-0.1.json +13 -13
  15. package/dsh-ecosystem-spec/registry/registry-0.15.json +149 -149
  16. package/lib/types/cc/hyperlink.d.ts +7 -1
  17. package/lib/types/cc/hyperlink.d.ts.map +1 -1
  18. package/lib/types/cc/hyperlink.js +3 -2
  19. package/lib/types/cc/markdown.d.ts.map +1 -1
  20. package/lib/types/cc/markdown.js +33 -3
  21. package/lib/types/cc/sessionColors.d.ts +27 -0
  22. package/lib/types/cc/sessionColors.d.ts.map +1 -0
  23. package/lib/types/cc/sessionColors.js +39 -0
  24. package/lib/types/commands.d.ts.map +1 -1
  25. package/lib/types/commands.js +10 -2
  26. package/lib/types/components/ActivityPicker.d.ts +4 -1
  27. package/lib/types/components/ActivityPicker.d.ts.map +1 -1
  28. package/lib/types/components/ActivityPicker.js +2 -2
  29. package/lib/types/components/AutoRecapRow.d.ts +23 -0
  30. package/lib/types/components/AutoRecapRow.d.ts.map +1 -0
  31. package/lib/types/components/AutoRecapRow.js +23 -0
  32. package/lib/types/components/BtwPanel.d.ts.map +1 -1
  33. package/lib/types/components/BtwPanel.js +1 -1
  34. package/lib/types/components/Chat/SubagentMessage.d.ts +2 -1
  35. package/lib/types/components/Chat/SubagentMessage.d.ts.map +1 -1
  36. package/lib/types/components/Chat/SubagentMessage.js +11 -3
  37. package/lib/types/components/ColorPicker.d.ts +17 -0
  38. package/lib/types/components/ColorPicker.d.ts.map +1 -0
  39. package/lib/types/components/ColorPicker.js +20 -0
  40. package/lib/types/components/CommandSuggestions.d.ts +23 -4
  41. package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
  42. package/lib/types/components/CommandSuggestions.js +41 -14
  43. package/lib/types/components/ContextBarView.d.ts +33 -0
  44. package/lib/types/components/ContextBarView.d.ts.map +1 -0
  45. package/lib/types/components/ContextBarView.js +46 -0
  46. package/lib/types/components/EffortInputBorder.d.ts +12 -1
  47. package/lib/types/components/EffortInputBorder.d.ts.map +1 -1
  48. package/lib/types/components/EffortInputBorder.js +22 -5
  49. package/lib/types/components/EffortSlider.d.ts +4 -1
  50. package/lib/types/components/EffortSlider.d.ts.map +1 -1
  51. package/lib/types/components/EffortSlider.js +4 -2
  52. package/lib/types/components/ExtensionDialog.js +6 -2
  53. package/lib/types/components/FileActionsPanel.d.ts +22 -0
  54. package/lib/types/components/FileActionsPanel.d.ts.map +1 -0
  55. package/lib/types/components/FileActionsPanel.js +28 -0
  56. package/lib/types/components/FileSuggestions.d.ts +26 -7
  57. package/lib/types/components/FileSuggestions.d.ts.map +1 -1
  58. package/lib/types/components/FileSuggestions.js +39 -12
  59. package/lib/types/components/GoalTodoPanel.d.ts +26 -2
  60. package/lib/types/components/GoalTodoPanel.d.ts.map +1 -1
  61. package/lib/types/components/GoalTodoPanel.js +86 -17
  62. package/lib/types/components/HelpMenu.d.ts +7 -1
  63. package/lib/types/components/HelpMenu.d.ts.map +1 -1
  64. package/lib/types/components/HelpMenu.js +12 -4
  65. package/lib/types/components/HistorySearchDialog.d.ts +4 -1
  66. package/lib/types/components/HistorySearchDialog.d.ts.map +1 -1
  67. package/lib/types/components/HistorySearchDialog.js +2 -2
  68. package/lib/types/components/LangPicker.d.ts +14 -0
  69. package/lib/types/components/LangPicker.d.ts.map +1 -0
  70. package/lib/types/components/LangPicker.js +17 -0
  71. package/lib/types/components/LoadedContextPanel.d.ts.map +1 -1
  72. package/lib/types/components/LoadedContextPanel.js +3 -1
  73. package/lib/types/components/Markdown.d.ts.map +1 -1
  74. package/lib/types/components/Markdown.js +12 -3
  75. package/lib/types/components/MessageList.d.ts +45 -2
  76. package/lib/types/components/MessageList.d.ts.map +1 -1
  77. package/lib/types/components/MessageList.js +560 -41
  78. package/lib/types/components/ModelPicker.d.ts +27 -2
  79. package/lib/types/components/ModelPicker.d.ts.map +1 -1
  80. package/lib/types/components/ModelPicker.js +26 -6
  81. package/lib/types/components/PermissionsPicker.d.ts +21 -0
  82. package/lib/types/components/PermissionsPicker.d.ts.map +1 -0
  83. package/lib/types/components/PermissionsPicker.js +27 -0
  84. package/lib/types/components/PlanPicker.d.ts +15 -0
  85. package/lib/types/components/PlanPicker.d.ts.map +1 -0
  86. package/lib/types/components/PlanPicker.js +18 -0
  87. package/lib/types/components/PresetPicker.d.ts +4 -1
  88. package/lib/types/components/PresetPicker.d.ts.map +1 -1
  89. package/lib/types/components/PresetPicker.js +2 -2
  90. package/lib/types/components/PromptInput.d.ts +4 -3
  91. package/lib/types/components/PromptInput.d.ts.map +1 -1
  92. package/lib/types/components/PromptInput.js +602 -75
  93. package/lib/types/components/RecapPanel.d.ts +25 -0
  94. package/lib/types/components/RecapPanel.d.ts.map +1 -0
  95. package/lib/types/components/RecapPanel.js +55 -0
  96. package/lib/types/components/RewindPicker.d.ts +12 -1
  97. package/lib/types/components/RewindPicker.d.ts.map +1 -1
  98. package/lib/types/components/RewindPicker.js +6 -4
  99. package/lib/types/components/ScrollbarGutter.d.ts +28 -0
  100. package/lib/types/components/ScrollbarGutter.d.ts.map +1 -0
  101. package/lib/types/components/ScrollbarGutter.js +119 -0
  102. package/lib/types/components/Select.d.ts +8 -1
  103. package/lib/types/components/Select.d.ts.map +1 -1
  104. package/lib/types/components/Select.js +4 -2
  105. package/lib/types/components/SkillsPicker.d.ts +4 -1
  106. package/lib/types/components/SkillsPicker.d.ts.map +1 -1
  107. package/lib/types/components/SkillsPicker.js +2 -2
  108. package/lib/types/components/SubagentCard.d.ts +2 -1
  109. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  110. package/lib/types/components/SubagentCard.js +9 -2
  111. package/lib/types/components/SubagentDashboard.d.ts +4 -0
  112. package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
  113. package/lib/types/components/SubagentDashboard.js +9 -1
  114. package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
  115. package/lib/types/components/SubagentDetailScene.js +5 -4
  116. package/lib/types/components/SuggestionCard.d.ts +65 -0
  117. package/lib/types/components/SuggestionCard.d.ts.map +1 -0
  118. package/lib/types/components/SuggestionCard.js +77 -0
  119. package/lib/types/components/ThemePicker.d.ts +4 -1
  120. package/lib/types/components/ThemePicker.d.ts.map +1 -1
  121. package/lib/types/components/ThemePicker.js +2 -2
  122. package/lib/types/components/ThinkingToggle.d.ts +4 -1
  123. package/lib/types/components/ThinkingToggle.d.ts.map +1 -1
  124. package/lib/types/components/ThinkingToggle.js +2 -2
  125. package/lib/types/components/TimelineRail.d.ts +53 -0
  126. package/lib/types/components/TimelineRail.d.ts.map +1 -0
  127. package/lib/types/components/TimelineRail.js +197 -0
  128. package/lib/types/components/WorkspaceFlowPicker.d.ts +6 -1
  129. package/lib/types/components/WorkspaceFlowPicker.d.ts.map +1 -1
  130. package/lib/types/components/WorkspaceFlowPicker.js +4 -2
  131. package/lib/types/components/WorkspaceMenuPicker.d.ts +19 -0
  132. package/lib/types/components/WorkspaceMenuPicker.d.ts.map +1 -0
  133. package/lib/types/components/WorkspaceMenuPicker.js +19 -0
  134. package/lib/types/components/WorkspacePicker.d.ts +4 -1
  135. package/lib/types/components/WorkspacePicker.d.ts.map +1 -1
  136. package/lib/types/components/WorkspacePicker.js +2 -2
  137. package/lib/types/components/approvals/ApprovalPanel.d.ts.map +1 -1
  138. package/lib/types/components/approvals/ApprovalPanel.js +5 -1
  139. package/lib/types/components/design-system/ListItem.d.ts +8 -1
  140. package/lib/types/components/design-system/ListItem.d.ts.map +1 -1
  141. package/lib/types/components/design-system/ListItem.js +8 -3
  142. package/lib/types/components/design-system/ThemeProvider.d.ts +7 -0
  143. package/lib/types/components/design-system/ThemeProvider.d.ts.map +1 -1
  144. package/lib/types/components/design-system/ThemeProvider.js +2 -1
  145. package/lib/types/components/messages/AssistantTextMessage.d.ts +5 -2
  146. package/lib/types/components/messages/AssistantTextMessage.d.ts.map +1 -1
  147. package/lib/types/components/messages/AssistantTextMessage.js +6 -2
  148. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +2 -1
  149. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  150. package/lib/types/components/messages/AssistantThinkingMessage.js +10 -4
  151. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +15 -1
  152. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  153. package/lib/types/components/messages/AssistantToolUseMessage.js +37 -7
  154. package/lib/types/components/messages/UserPromptMessage.d.ts +2 -1
  155. package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
  156. package/lib/types/components/questions/AskUserQuestionPanel.d.ts +7 -3
  157. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  158. package/lib/types/components/questions/AskUserQuestionPanel.js +75 -11
  159. package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
  160. package/lib/types/components/questions/PlanReviewPanel.js +13 -2
  161. package/lib/types/components/sessions/SessionListRow.d.ts +4 -1
  162. package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
  163. package/lib/types/components/sessions/SessionListRow.js +4 -2
  164. package/lib/types/components/trajectory/HotspotView.d.ts +7 -1
  165. package/lib/types/components/trajectory/HotspotView.d.ts.map +1 -1
  166. package/lib/types/components/trajectory/HotspotView.js +8 -2
  167. package/lib/types/components/trajectory/Ledger.d.ts +9 -1
  168. package/lib/types/components/trajectory/Ledger.d.ts.map +1 -1
  169. package/lib/types/components/trajectory/Ledger.js +23 -5
  170. package/lib/types/components/trajectory/WaveBand.d.ts +10 -1
  171. package/lib/types/components/trajectory/WaveBand.d.ts.map +1 -1
  172. package/lib/types/components/trajectory/WaveBand.js +7 -2
  173. package/lib/types/dsh-adapter/channel.d.ts +117 -7
  174. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  175. package/lib/types/dsh-adapter/channel.js +1301 -122
  176. package/lib/types/dsh-adapter/compat/index.d.ts +8 -6
  177. package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -1
  178. package/lib/types/dsh-adapter/compat/index.js +8 -6
  179. package/lib/types/dsh-adapter/compat/sessionLog.d.ts +150 -0
  180. package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -1
  181. package/lib/types/dsh-adapter/compat/sessionLog.js +518 -41
  182. package/lib/types/dsh-adapter/contract.d.ts +1 -1
  183. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  184. package/lib/types/dsh-adapter/contract.js +1 -0
  185. package/lib/types/dsh-adapter/extension-events.d.ts +1 -1
  186. package/lib/types/dsh-adapter/extension-events.d.ts.map +1 -1
  187. package/lib/types/dsh-adapter/index.d.ts +20 -2
  188. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  189. package/lib/types/dsh-adapter/index.js +9 -1
  190. package/lib/types/dsh-adapter/plugin.d.ts +0 -9
  191. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  192. package/lib/types/dsh-adapter/plugin.js +453 -14
  193. package/lib/types/dsh-adapter/presets.d.ts +18 -0
  194. package/lib/types/dsh-adapter/presets.d.ts.map +1 -1
  195. package/lib/types/dsh-adapter/presets.js +31 -0
  196. package/lib/types/dsh-adapter/providerWizard.d.ts +29 -1
  197. package/lib/types/dsh-adapter/providerWizard.d.ts.map +1 -1
  198. package/lib/types/dsh-adapter/providerWizard.js +89 -5
  199. package/lib/types/dsh-adapter/questions.d.ts +19 -2
  200. package/lib/types/dsh-adapter/questions.d.ts.map +1 -1
  201. package/lib/types/dsh-adapter/questions.js +53 -10
  202. package/lib/types/dsh-adapter/recap.d.ts +49 -0
  203. package/lib/types/dsh-adapter/recap.d.ts.map +1 -0
  204. package/lib/types/dsh-adapter/recap.js +121 -0
  205. package/lib/types/dsh-adapter/sessionTree.d.ts +314 -0
  206. package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -0
  207. package/lib/types/dsh-adapter/sessionTree.js +954 -0
  208. package/lib/types/dsh-adapter/shortcuts.d.ts +15 -44
  209. package/lib/types/dsh-adapter/shortcuts.d.ts.map +1 -1
  210. package/lib/types/dsh-adapter/shortcuts.js +28 -165
  211. package/lib/types/dsh-adapter/types.d.ts +1 -1
  212. package/lib/types/dsh-adapter/types.d.ts.map +1 -1
  213. package/lib/types/herdr.js +1 -1
  214. package/lib/types/i18n.d.ts +770 -181
  215. package/lib/types/i18n.d.ts.map +1 -1
  216. package/lib/types/i18n.js +257 -80
  217. package/lib/types/ink/components/AlternateScreen.d.ts.map +1 -1
  218. package/lib/types/ink/components/AlternateScreen.js +13 -1
  219. package/lib/types/ink/components/App.d.ts +12 -1
  220. package/lib/types/ink/components/App.d.ts.map +1 -1
  221. package/lib/types/ink/components/App.js +101 -4
  222. package/lib/types/ink/components/ClockContext.d.ts.map +1 -1
  223. package/lib/types/ink/components/ClockContext.js +2 -0
  224. package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
  225. package/lib/types/ink/components/ScrollBox.js +170 -91
  226. package/lib/types/ink/constants.d.ts +9 -0
  227. package/lib/types/ink/constants.d.ts.map +1 -1
  228. package/lib/types/ink/constants.js +9 -0
  229. package/lib/types/ink/events/click-event.d.ts +7 -16
  230. package/lib/types/ink/events/click-event.d.ts.map +1 -1
  231. package/lib/types/ink/events/click-event.js +16 -19
  232. package/lib/types/ink/events/event-handlers.d.ts +11 -1
  233. package/lib/types/ink/events/event-handlers.d.ts.map +1 -1
  234. package/lib/types/ink/events/event-handlers.js +2 -0
  235. package/lib/types/ink/events/input-event.d.ts +9 -0
  236. package/lib/types/ink/events/input-event.d.ts.map +1 -1
  237. package/lib/types/ink/events/input-event.js +4 -0
  238. package/lib/types/ink/events/pointer-event.d.ts +61 -0
  239. package/lib/types/ink/events/pointer-event.d.ts.map +1 -0
  240. package/lib/types/ink/events/pointer-event.js +61 -0
  241. package/lib/types/ink/events/wheel-event.d.ts +17 -0
  242. package/lib/types/ink/events/wheel-event.d.ts.map +1 -0
  243. package/lib/types/ink/events/wheel-event.js +20 -0
  244. package/lib/types/ink/geometry-trace.d.ts +51 -0
  245. package/lib/types/ink/geometry-trace.d.ts.map +1 -0
  246. package/lib/types/ink/geometry-trace.js +83 -0
  247. package/lib/types/ink/hit-test.d.ts +56 -1
  248. package/lib/types/ink/hit-test.d.ts.map +1 -1
  249. package/lib/types/ink/hit-test.js +146 -8
  250. package/lib/types/ink/ink.d.ts +58 -1
  251. package/lib/types/ink/ink.d.ts.map +1 -1
  252. package/lib/types/ink/ink.js +230 -29
  253. package/lib/types/ink/log-update.d.ts.map +1 -1
  254. package/lib/types/ink/log-update.js +21 -0
  255. package/lib/types/ink/node-cache.d.ts +5 -0
  256. package/lib/types/ink/node-cache.d.ts.map +1 -1
  257. package/lib/types/ink/parse-keypress.d.ts +8 -0
  258. package/lib/types/ink/parse-keypress.d.ts.map +1 -1
  259. package/lib/types/ink/parse-keypress.js +101 -12
  260. package/lib/types/ink/render-node-to-output.d.ts +10 -0
  261. package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
  262. package/lib/types/ink/render-node-to-output.js +111 -18
  263. package/lib/types/ink/timeline-rail.d.ts +138 -0
  264. package/lib/types/ink/timeline-rail.d.ts.map +1 -0
  265. package/lib/types/ink/timeline-rail.js +179 -0
  266. package/lib/types/ink/wrap-text.d.ts.map +1 -1
  267. package/lib/types/ink/wrap-text.js +47 -5
  268. package/lib/types/migrationPrefs.d.ts +60 -0
  269. package/lib/types/migrationPrefs.d.ts.map +1 -0
  270. package/lib/types/migrationPrefs.js +97 -0
  271. package/lib/types/modelGroups.d.ts +72 -0
  272. package/lib/types/modelGroups.d.ts.map +1 -0
  273. package/lib/types/modelGroups.js +97 -0
  274. package/lib/types/modelRecents.d.ts +39 -0
  275. package/lib/types/modelRecents.d.ts.map +1 -0
  276. package/lib/types/modelRecents.js +97 -0
  277. package/lib/types/native-ts/yoga-layout/index.d.ts +11 -0
  278. package/lib/types/native-ts/yoga-layout/index.d.ts.map +1 -1
  279. package/lib/types/native-ts/yoga-layout/index.js +31 -1
  280. package/lib/types/oauth.d.ts +15 -0
  281. package/lib/types/oauth.d.ts.map +1 -0
  282. package/lib/types/oauth.js +14 -0
  283. package/lib/types/reload.d.ts +109 -0
  284. package/lib/types/reload.d.ts.map +1 -0
  285. package/lib/types/reload.js +118 -0
  286. package/lib/types/screens/Chat.d.ts +3 -1
  287. package/lib/types/screens/Chat.d.ts.map +1 -1
  288. package/lib/types/screens/Chat.js +1377 -371
  289. package/lib/types/screens/SessionBrowser.d.ts.map +1 -1
  290. package/lib/types/screens/SessionBrowser.js +56 -29
  291. package/lib/types/screens/SessionTree.d.ts +27 -0
  292. package/lib/types/screens/SessionTree.d.ts.map +1 -0
  293. package/lib/types/screens/SessionTree.js +555 -0
  294. package/lib/types/screens/Settings.d.ts.map +1 -1
  295. package/lib/types/screens/Settings.js +64 -22
  296. package/lib/types/screens/StatusLine.d.ts +0 -8
  297. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  298. package/lib/types/screens/StatusLine.js +224 -45
  299. package/lib/types/screens/StatusMetrics.d.ts +35 -3
  300. package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
  301. package/lib/types/screens/StatusMetrics.js +63 -8
  302. package/lib/types/screens/TrajectoryScene.d.ts.map +1 -1
  303. package/lib/types/screens/TrajectoryScene.js +81 -14
  304. package/lib/types/screens/chatOverlay.d.ts +237 -0
  305. package/lib/types/screens/chatOverlay.d.ts.map +1 -0
  306. package/lib/types/screens/chatOverlay.js +116 -0
  307. package/lib/types/tips.d.ts.map +1 -1
  308. package/lib/types/tips.js +64 -10
  309. package/lib/types/tuiDisplayPrefs.d.ts +15 -0
  310. package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
  311. package/lib/types/tuiDisplayPrefs.js +9 -0
  312. package/lib/types/update.d.ts +139 -0
  313. package/lib/types/update.d.ts.map +1 -1
  314. package/lib/types/update.js +382 -30
  315. package/lib/types/utils/debug.d.ts +10 -0
  316. package/lib/types/utils/debug.d.ts.map +1 -1
  317. package/lib/types/utils/debug.js +24 -0
  318. package/lib/types/utils/fileTarget.d.ts +46 -0
  319. package/lib/types/utils/fileTarget.d.ts.map +1 -0
  320. package/lib/types/utils/fileTarget.js +178 -0
  321. package/lib/types/utils/keymap.d.ts +134 -0
  322. package/lib/types/utils/keymap.d.ts.map +1 -0
  323. package/lib/types/utils/keymap.js +311 -0
  324. package/lib/types/utils/mentions.d.ts +25 -2
  325. package/lib/types/utils/mentions.d.ts.map +1 -1
  326. package/lib/types/utils/mentions.js +69 -10
  327. package/lib/types/utils/openExternal.d.ts +50 -0
  328. package/lib/types/utils/openExternal.d.ts.map +1 -0
  329. package/lib/types/utils/openExternal.js +170 -0
  330. package/lib/types/utils/paths.d.ts.map +1 -1
  331. package/lib/types/utils/paths.js +1 -0
  332. package/node_modules/@deepseek-harness-tui/dsh-auth/LICENSE +21 -0
  333. package/node_modules/@deepseek-harness-tui/dsh-auth/README.md +140 -0
  334. package/node_modules/@deepseek-harness-tui/dsh-auth/cordis.patch.yml +11 -0
  335. package/node_modules/@deepseek-harness-tui/dsh-auth/dsh-plugin.json +44 -0
  336. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/command.d.ts +14 -0
  337. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/command.js +67 -0
  338. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/credentials.d.ts +64 -0
  339. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/credentials.js +170 -0
  340. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/index.d.ts +79 -0
  341. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/index.js +196 -0
  342. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/interaction.d.ts +68 -0
  343. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/interaction.js +193 -0
  344. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/opener.d.ts +32 -0
  345. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/opener.js +101 -0
  346. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/profiles.d.ts +31 -0
  347. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/profiles.js +68 -0
  348. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/service.d.ts +69 -0
  349. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/service.js +129 -0
  350. package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +70 -0
  351. package/node_modules/@dsh-std/command/CHANGELOG.md +8 -8
  352. package/node_modules/@dsh-std/command/LICENSE +21 -21
  353. package/node_modules/@dsh-std/command/README.md +26 -26
  354. package/node_modules/@dsh-std/command/README.zh.md +28 -28
  355. package/node_modules/@dsh-std/command/lib/index.js.map +1 -1
  356. package/node_modules/@dsh-std/command/package.json +22 -22
  357. package/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
  358. package/node_modules/@dsh-std/connection/LICENSE +21 -21
  359. package/node_modules/@dsh-std/connection/README.md +42 -42
  360. package/node_modules/@dsh-std/connection/README.zh.md +42 -42
  361. package/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
  362. package/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  363. package/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
  364. package/node_modules/@dsh-std/connection/package.json +20 -20
  365. package/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  366. package/node_modules/@dsh-std/core/LICENSE +21 -21
  367. package/node_modules/@dsh-std/core/README.md +13 -13
  368. package/node_modules/@dsh-std/core/README.zh.md +13 -13
  369. package/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  370. package/node_modules/@dsh-std/core/package.json +21 -21
  371. package/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
  372. package/node_modules/@dsh-std/manifest/LICENSE +21 -21
  373. package/node_modules/@dsh-std/manifest/README.md +5 -5
  374. package/node_modules/@dsh-std/manifest/README.zh.md +5 -5
  375. package/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
  376. package/node_modules/@dsh-std/manifest/package.json +20 -20
  377. package/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
  378. package/node_modules/@dsh-std/messages/CHANGELOG.md +8 -8
  379. package/node_modules/@dsh-std/messages/LICENSE +21 -21
  380. package/node_modules/@dsh-std/messages/README.md +5 -5
  381. package/node_modules/@dsh-std/messages/README.zh.md +7 -7
  382. package/node_modules/@dsh-std/messages/lib/index.js.map +1 -1
  383. package/node_modules/@dsh-std/messages/package.json +20 -20
  384. package/node_modules/@dsh-std/messages/schema/message-observer-envelope-0.15.schema.json +54 -54
  385. package/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
  386. package/node_modules/@dsh-std/presentation/LICENSE +21 -21
  387. package/node_modules/@dsh-std/presentation/README.md +27 -27
  388. package/node_modules/@dsh-std/presentation/README.zh.md +29 -29
  389. package/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
  390. package/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
  391. package/node_modules/@dsh-std/presentation/package.json +25 -25
  392. package/node_modules/@dsh-std/storage/CHANGELOG.md +8 -8
  393. package/node_modules/@dsh-std/storage/LICENSE +21 -21
  394. package/node_modules/@dsh-std/storage/README.md +5 -5
  395. package/node_modules/@dsh-std/storage/README.zh.md +7 -7
  396. package/node_modules/@dsh-std/storage/lib/index.js.map +1 -1
  397. package/node_modules/@dsh-std/storage/package.json +20 -20
  398. package/node_modules/@dsh-std/storage/schema/local-storage-0.15.schema.json +56 -56
  399. package/package.json +19 -5
  400. package/presets/liangshen/.dsh-tui-managed.json +1 -1
  401. package/presets/liangshen/instruction-hint.mjs +8 -0
  402. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
  403. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/LICENSE +21 -21
  404. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.md +42 -42
  405. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.zh.md +42 -42
  406. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
  407. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  408. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
  409. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/package.json +20 -20
  410. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  411. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/LICENSE +21 -21
  412. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.md +13 -13
  413. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.zh.md +13 -13
  414. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  415. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/package.json +21 -21
  416. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
  417. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/LICENSE +21 -21
  418. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.md +5 -5
  419. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.zh.md +5 -5
  420. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
  421. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/package.json +20 -20
  422. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
  423. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
  424. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/LICENSE +21 -21
  425. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.md +27 -27
  426. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.zh.md +29 -29
  427. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
  428. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
  429. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/package.json +25 -25
  430. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  431. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/LICENSE +21 -21
  432. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.md +13 -13
  433. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.zh.md +13 -13
  434. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  435. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/package.json +21 -21
  436. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  437. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/LICENSE +21 -21
  438. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.md +13 -13
  439. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.zh.md +13 -13
  440. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  441. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/package.json +21 -21
  442. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  443. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/LICENSE +21 -21
  444. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.md +13 -13
  445. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.zh.md +13 -13
  446. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  447. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/package.json +21 -21
  448. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
  449. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/LICENSE +21 -21
  450. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.md +42 -42
  451. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.zh.md +42 -42
  452. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
  453. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  454. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
  455. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/package.json +20 -20
  456. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  457. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/LICENSE +21 -21
  458. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.md +13 -13
  459. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.zh.md +13 -13
  460. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  461. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/package.json +21 -21
  462. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  463. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/LICENSE +21 -21
  464. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.md +13 -13
  465. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.zh.md +13 -13
  466. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  467. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/package.json +21 -21
@@ -1,4 +1,5 @@
1
1
  import type { DOMElement } from './dom.js';
2
+ import type { Rectangle } from './layout/geometry.js';
2
3
  import type Output from './output.js';
3
4
  import type { Screen } from './screen.js';
4
5
  import { type StyledSegment } from './squash-text-nodes.js';
@@ -22,6 +23,15 @@ export type ScrollHint = {
22
23
  bottom: number;
23
24
  delta: number;
24
25
  };
26
+ export type AbsoluteHitEntry = {
27
+ node: DOMElement;
28
+ rect: Rectangle;
29
+ };
30
+ /**
31
+ * The current frame's absolute-positioned nodes in paint order.
32
+ * @returns read-only list; reverse-iterate for topmost-first hit-testing.
33
+ */
34
+ export declare function getAbsoluteHitList(): readonly AbsoluteHitEntry[];
25
35
  /** Reset the scroll hint for the next frame and rotate the absolute-rect buffers. */
26
36
  export declare function resetScrollHint(): void;
27
37
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"render-node-to-output.d.ts","sourceRoot":"","sources":["../../../src/ink/render-node-to-output.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAK1C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAErC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAqBxC,6CAA6C;AAC7C,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAOD;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAWvE,qFAAqF;AACrF,wBAAgB,eAAe,IAAI,IAAI,CAItC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAEjD;AASD,8DAA8D;AAC9D,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,UAAU,GAAG,IAAI,CAEtD;AAgBD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;CACvB,CAAA;AAGD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,IAAI,YAAY,EAAE,CAIpD;AAoFD;;;;;GAKG;AACH,iBAAS,qBAAqB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE,CASlE;AAED;;;;;;;;;;;GAWG;AACH,iBAAS,wBAAwB,CAC/B,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,aAAa,EAAE,EACzB,aAAa,EAAE,MAAM,EAAE,EACvB,aAAa,EAAE,MAAM,EACrB,WAAW,GAAE,OAAe,GAC3B,MAAM,CA0GR;AA+DD;;;;;;;;;GASG;AACH,iBAAS,kBAAkB,CACzB,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;IACP,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IAM9B,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,wBAAwB,CAAC,EAAE,KAAK,CAAA;CACjC,GACA,IAAI,CAo4BN;AAyOD,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,CAAA;AAE1D,eAAe,kBAAkB,CAAA"}
1
+ {"version":3,"file":"render-node-to-output.d.ts","sourceRoot":"","sources":["../../../src/ink/render-node-to-output.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAG1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAGrD,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAErC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAqBxC,6CAA6C;AAC7C,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAOD;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAkBvE,MAAM,MAAM,gBAAgB,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,CAAA;AAGpE;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,SAAS,gBAAgB,EAAE,CAEhE;AAED,qFAAqF;AACrF,wBAAgB,eAAe,IAAI,IAAI,CAKtC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAEjD;AASD,8DAA8D;AAC9D,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,UAAU,GAAG,IAAI,CAEtD;AAgBD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;CACvB,CAAA;AAGD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,IAAI,YAAY,EAAE,CAIpD;AAoFD;;;;;GAKG;AACH,iBAAS,qBAAqB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE,CASlE;AAED;;;;;;;;;;;GAWG;AACH,iBAAS,wBAAwB,CAC/B,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,aAAa,EAAE,EACzB,aAAa,EAAE,MAAM,EAAE,EACvB,aAAa,EAAE,MAAM,EACrB,WAAW,GAAE,OAAe,GAC3B,MAAM,CA0GR;AA+DD;;;;;;;;;GASG;AACH,iBAAS,kBAAkB,CACzB,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;IACP,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IAM9B,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,wBAAwB,CAAC,EAAE,KAAK,CAAA;CACjC,GACA,IAAI,CAq9BN;AA0OD,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,CAAA;AAE1D,eAAe,kBAAkB,CAAA"}
@@ -1,5 +1,6 @@
1
1
  import indentString from 'indent-string';
2
2
  import { applyTextStyles } from './colorize.js';
3
+ import { GEOMETRY_TRACE_ENABLED, noteScrollGeometry } from './geometry-trace.js';
3
4
  import getMaxWidth from './get-max-width.js';
4
5
  import { LayoutDisplay, LayoutEdge } from './layout/node.js';
5
6
  import { nodeCache, pendingClears } from './node-cache.js';
@@ -41,11 +42,20 @@ let scrollHint = null;
41
42
  // still have the rect.
42
43
  let absoluteRectsPrev = [];
43
44
  let absoluteRectsCur = [];
45
+ let absoluteHitList = [];
46
+ /**
47
+ * The current frame's absolute-positioned nodes in paint order.
48
+ * @returns read-only list; reverse-iterate for topmost-first hit-testing.
49
+ */
50
+ export function getAbsoluteHitList() {
51
+ return absoluteHitList;
52
+ }
44
53
  /** Reset the scroll hint for the next frame and rotate the absolute-rect buffers. */
45
54
  export function resetScrollHint() {
46
55
  scrollHint = null;
47
56
  absoluteRectsPrev = absoluteRectsCur;
48
57
  absoluteRectsCur = [];
58
+ absoluteHitList = [];
49
59
  }
50
60
  /**
51
61
  * The scroll hint captured this frame, or null.
@@ -359,18 +369,34 @@ function renderNodeToOutput(node, output, options) {
359
369
  let y = offsetY + yogaTop;
360
370
  const width = yogaNode.getComputedWidth();
361
371
  const height = yogaNode.getComputedHeight();
362
- // Absolute-positioned overlays (e.g. autocomplete menus with bottom='100%')
363
- // can compute negative screen y when they extend above the viewport. Without
364
- // clamping, setCellAt drops cells at y<0, clipping the TOP of the content
365
- // (best matches in an autocomplete). By clamping to 0, we shift the element
366
- // down so the top rows are visible and the bottom overflows below — the
367
- // opaque prop ensures it paints over whatever is underneath.
368
- if (y < 0 && node.style.position === 'absolute') {
369
- y = 0;
370
- }
372
+ // Absolute-positioned overlays anchored above their parent
373
+ // (bottom='100%') compute negative screen y when their content is
374
+ // taller than the space above the anchor. Do NOT clamp y to 0 here:
375
+ // shifting the node down breaks the bottom-anchoring contract — the
376
+ // panel's BOTTOM would overflow past the anchor and paint over the
377
+ // composer/status rows below it (small-terminal overlay reports).
378
+ // Instead let the y<0 rows clip naturally: setCellAt drops cells above
379
+ // row 0 and blitRegion clamps in screen space, so the panel keeps its
380
+ // bottom pinned at the anchor and only loses its topmost rows — the
381
+ // same semantics as CSS clipping above the containing block. Producers
382
+ // prevent the case entirely by maxHeight-ing the overlay to the actual
383
+ // space above the anchor (OverlayAbove), so clipping is the last
384
+ // resort, not the layout.
371
385
  // Check if we can skip this subtree (clean node with unchanged layout).
372
386
  // Blit cells from previous screen instead of re-rendering.
373
387
  const cached = nodeCache.get(node);
388
+ // The node's EFFECTIVE background = its own + the inherited one. When it
389
+ // changed since the last frame (hover on/off toggles a row's
390
+ // backgroundColor, a parent's bg swap changes every child's inherited
391
+ // value), prevScreen still holds the OLD background — a clean child
392
+ // blitting it would resurrect the stale color (stuck hover highlights:
393
+ // the row's fill is skipped once the bg is removed, its clean children
394
+ // then blit the previous bg'd cells, the frame equals prevScreen, the
395
+ // diff finds nothing, and the highlight never clears). Compare against
396
+ // the value recorded at the previous render and refuse the blit when it
397
+ // moved.
398
+ const effectiveBg = node.style.backgroundColor ?? inheritedBackgroundColor;
399
+ const bgChanged = cached?.bg !== effectiveBg;
374
400
  if (!node.dirty &&
375
401
  !skipSelfBlit &&
376
402
  node.pendingScrollDelta === undefined &&
@@ -379,6 +405,7 @@ function renderNodeToOutput(node, output, options) {
379
405
  cached.y === y &&
380
406
  cached.width === width &&
381
407
  cached.height === height &&
408
+ !bgChanged &&
382
409
  prevScreen) {
383
410
  const fx = Math.floor(x);
384
411
  const fy = Math.floor(y);
@@ -387,6 +414,7 @@ function renderNodeToOutput(node, output, options) {
387
414
  output.blit(prevScreen, fx, fy, fw, fh);
388
415
  if (node.style.position === 'absolute') {
389
416
  absoluteRectsCur.push(cached);
417
+ absoluteHitList.push({ node, rect: cached });
390
418
  }
391
419
  // Absolute descendants can paint outside this node's layout bounds
392
420
  // (e.g. a slash menu with position='absolute' bottom='100%' floats
@@ -593,7 +621,29 @@ function renderNodeToOutput(node, output, options) {
593
621
  // within the viewport (equal to the scroll container's
594
622
  // paddingTop), and innerHeight already subtracts padding, so
595
623
  // including it double-counts padding and inflates maxScroll.
596
- const scrollHeight = contentYoga?.getComputedHeight() ?? 0;
624
+ let scrollHeight = contentYoga?.getComputedHeight() ?? 0;
625
+ // Defensive extent floor: the wrapper's Yoga height can land ONE LINE
626
+ // short of its children's laid-out extent (the engine's flex-basis
627
+ // measure cache and the child's final subtree layout can disagree by
628
+ // a row — measured on resume of a long session: wrapper 286 while the
629
+ // last row's bottom sat at 287, stable across forced re-layouts). A
630
+ // short scrollHeight clamps maxScroll below the real bottom, so the
631
+ // sticky pin parks the viewport a line up and the tail line culls
632
+ // against the viewport edge — permanently invisible AND unreachable
633
+ // (no scroll position ever shows it; the user loses the newest
634
+ // message). The children's real extent is the authoritative floor.
635
+ // O(direct children) — the windowed list keeps this tiny, and the
636
+ // painter walks the same nodes right below.
637
+ if (content !== undefined) {
638
+ for (const child of content.childNodes) {
639
+ const childYoga = child.yogaNode;
640
+ if (childYoga === undefined)
641
+ continue;
642
+ const bottom = childYoga.getComputedTop() + childYoga.getComputedHeight();
643
+ if (bottom > scrollHeight)
644
+ scrollHeight = bottom;
645
+ }
646
+ }
597
647
  // Capture previous scroll bounds BEFORE overwriting — the at-bottom
598
648
  // follow check compares against last frame's max.
599
649
  const prevScrollHeight = node.scrollHeight ?? scrollHeight;
@@ -735,7 +785,17 @@ function renderNodeToOutput(node, output, options) {
735
785
  // Keep the pre-frame position on a shrink frame (measurement
736
786
  // artifact) instead of clamping to the shrunken maxScroll — the
737
787
  // clamp would persist the yank even after content grows back.
738
- let scrollTop = shrunk ? cur : Math.max(0, Math.min(cur, maxScroll));
788
+ // Exception: a STICKY view must stay pinned to the bottom. A width
789
+ // change clears MessageList's row-height cache, collapsing the
790
+ // estimated scrollHeight; freezing the pre-shrink scrollTop then
791
+ // parks it PAST the whole shrunken content — every child culls and
792
+ // the frame paints only the bottom chrome. With the resize erase
793
+ // (needsEraseBeforePaint) that lands as a pure blank screen with
794
+ // just the input box, and an idle app produces no follow-up frame
795
+ // to heal it (user-reported full-screen loss on pane-width jitter —
796
+ // issue #421; repro-resize-blank). Clamping a sticky view to the shrunken
797
+ // maxScroll is exactly its contract — show the bottom.
798
+ let scrollTop = shrunk && !sticky ? cur : Math.max(0, Math.min(cur, maxScroll));
739
799
  // Virtual-scroll clamp: if scrollTop raced past the currently-mounted
740
800
  // range (burst PageUp before React re-renders), render at the EDGE of
741
801
  // the mounted children instead of blank spacer. Do NOT write back to
@@ -744,7 +804,15 @@ function renderNodeToOutput(node, output, options) {
744
804
  // the right range. Not scheduling scrollDrainNode here keeps the
745
805
  // clamp passive — React's commit → resetAfterCommit → onRender will
746
806
  // paint again with fresh bounds.
747
- const clamped = Math.max(cMin ?? -Infinity, Math.min(scrollTop, cMax ?? Infinity));
807
+ // Cap both bounds at maxScroll: the clamp bounds come from
808
+ // MessageList's height ESTIMATES while maxScroll comes from the
809
+ // frame's actual Yoga height. A width change resets the estimates
810
+ // (row-height cache clear), and a stale bound can point PAST the
811
+ // shrunken content bottom — the painted viewport then sits entirely
812
+ // below the content and every child culls to blank (the sticky
813
+ // full-screen loss — issue #421; repro-resize-blank). Nothing renderable exists
814
+ // below maxScroll regardless of what the estimates claim.
815
+ const clamped = Math.max(Math.min(cMin ?? -Infinity, maxScroll), Math.min(scrollTop, Math.min(cMax ?? Infinity, maxScroll)));
748
816
  node.scrollTop = scrollTop;
749
817
  // Clamp hitting top/bottom consumes any remainder. Set drainPending
750
818
  // only after clamp so a wasted no-op frame isn't scheduled.
@@ -752,6 +820,28 @@ function renderNodeToOutput(node, output, options) {
752
820
  node.pendingScrollDelta = undefined;
753
821
  if (node.pendingScrollDelta !== undefined)
754
822
  scrollDrainNode = node;
823
+ // Geometry forensics (#421/#433): everything that decides where this
824
+ // viewport painted — captured AFTER all clamps so the trace shows the
825
+ // final renderScrollTop, not the requested one.
826
+ if (GEOMETRY_TRACE_ENABLED) {
827
+ noteScrollGeometry({
828
+ sticky,
829
+ shrunk,
830
+ grew,
831
+ atBottom,
832
+ scrollTopBeforeFollow,
833
+ cur,
834
+ scrollTop,
835
+ renderScrollTop: clamped,
836
+ scrollHeight,
837
+ prevScrollHeight,
838
+ innerHeight,
839
+ maxScroll,
840
+ prevMaxScroll,
841
+ clampMin: cMin ?? null,
842
+ clampMax: cMax ?? null,
843
+ });
844
+ }
755
845
  // Wheel-drain selection translate (#438): the drain moved content
756
846
  // by (scrollTop - scrollTopBeforeFollow) rows this frame, minus
757
847
  // what at-bottom follow already reported above (followDelta is 0
@@ -1092,11 +1182,12 @@ function renderNodeToOutput(node, output, options) {
1092
1182
  // backgroundColor and opaque both disable child blit: the fill
1093
1183
  // overwrites the entire interior each render, so any child whose
1094
1184
  // layout position shifted would blit stale cells from prevScreen
1095
- // on top of the fresh fill. Previously opaque kept blit enabled
1096
- // on the assumption that plain-space fill + unchanged children =
1097
- // valid composite, but children CAN reposition (ScrollBox remeasure
1098
- // on re-render → /permissions body blanked on Down arrow, #25436).
1099
- ownBackgroundColor || node.style.opaque ? undefined : prevScreen, boxBackgroundColor);
1185
+ // on top of the fresh fill. bgChanged (effective background moved,
1186
+ // e.g. a hover highlight removed) must disable child blit for the
1187
+ // same reason: the old fill lives in prevScreen and the children's
1188
+ // blits would resurrect it — the frame then equals prevScreen and
1189
+ // the diff never clears the stale highlight.
1190
+ ownBackgroundColor || node.style.opaque || bgChanged ? undefined : prevScreen, boxBackgroundColor);
1100
1191
  }
1101
1192
  if (needsClip) {
1102
1193
  output.unclip();
@@ -1110,10 +1201,11 @@ function renderNodeToOutput(node, output, options) {
1110
1201
  renderChildren(node, output, x, y, hasRemovedChild, prevScreen, inheritedBackgroundColor);
1111
1202
  }
1112
1203
  // Cache layout bounds for dirty tracking
1113
- const rect = { x, y, width, height, top: yogaTop };
1204
+ const rect = { x, y, width, height, top: yogaTop, bg: effectiveBg };
1114
1205
  nodeCache.set(node, rect);
1115
1206
  if (node.style.position === 'absolute') {
1116
1207
  absoluteRectsCur.push(rect);
1208
+ absoluteHitList.push({ node, rect });
1117
1209
  }
1118
1210
  node.dirty = false;
1119
1211
  }
@@ -1227,6 +1319,7 @@ function blitEscapingAbsoluteDescendants(node, output, prevScreen, px, py, pw, p
1227
1319
  const cached = nodeCache.get(elem);
1228
1320
  if (cached) {
1229
1321
  absoluteRectsCur.push(cached);
1322
+ absoluteHitList.push({ node: elem, rect: cached });
1230
1323
  const cx = Math.floor(cached.x);
1231
1324
  const cy = Math.floor(cached.y);
1232
1325
  const cw = Math.floor(cached.width);
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Timeline rail — the pure geometry model behind the fullscreen
3
+ * transcript's turn navigator (a port of Grok Build's timeline sidebar
4
+ * semantics onto the dsh Ink tree).
5
+ *
6
+ * The rail is a 2-column gutter REPLACING the classic scrollbar: one tick
7
+ * per user turn, where tick position encodes CONVERSATION ORDER, not
8
+ * scroll proportion. Geometry is computed into a single frozen structure
9
+ * consumed by both the renderer and mouse hit-testing, so what you see is
10
+ * always what you can click ("看得到但点不中" impossible by construction).
11
+ *
12
+ * Viewport semantics (all derived from the same turn-top list, mirroring
13
+ * grok-pager's ScrollbackState):
14
+ *
15
+ * - active: the LAST turn whose prompt top is at-or-above the viewport
16
+ * top (the turn whose content owns the top row — "the turn being
17
+ * read"). When pre-turn content (logo / loaded-context panel) owns the
18
+ * top, the FIRST turn stands in. Never the newest-turn clamp: its
19
+ * one-step-off-bottom highlight leap is exactly what this rule avoids.
20
+ * - up target: the last turn STRICTLY above the viewport top. From
21
+ * mid-turn it first aligns the current turn's own prompt, and it can
22
+ * never name a trailing turn no scroll could bring to the top
23
+ * (the stuck-▲ bug).
24
+ * - down target: the FIRST turn whose prompt top is strictly below the
25
+ * viewport top AND reachable (top ≤ maxScroll — the renderer clamps
26
+ * scrollTop to maxScroll, so a turn below it could never own the top
27
+ * row; naming it would make ▼ repeat itself forever).
28
+ *
29
+ * Not ported (deliberately): ratatui Buffer drawing and Rust state
30
+ * organization — algorithms only, per the reference report.
31
+ */
32
+ /** Columns the rail reserves (widest tick glyph). */
33
+ export declare const RAIL_WIDTH = 2;
34
+ /** Terminals narrower than this hide the rail (transcript needs the cols). */
35
+ export declare const RAIL_MIN_TERMINAL_WIDTH = 60;
36
+ /** Fewer turns than this and the rail is noise. */
37
+ export declare const RAIL_MIN_TURNS = 2;
38
+ /** Stored preview cap (chars). Render paths re-truncate to card width. */
39
+ export declare const PREVIEW_MAX_CHARS = 120;
40
+ /** One user turn, as the rail sees it. Identity is the row id — never an
41
+ * array index (deletion / rewind / loadOlder would mis-target it). */
42
+ export interface TimelineTurn {
43
+ /** ChatRow id of the user message (jump/preview target). */
44
+ id: number;
45
+ /** Content-space top of the prompt TEXT (scrollTo(target) pins it to
46
+ * the viewport top). */
47
+ top: number;
48
+ /** First non-empty prompt line, char-capped (see clipPreview). */
49
+ preview: string;
50
+ /**
51
+ * True while the row sits BEFORE the fold window (older than the most
52
+ * recent MAX_RENDERED_ROWS rows): its top is unknown (unmounted since
53
+ * before the fold; `top` carries −1) and clicking the tick must first
54
+ * reveal the folded history (Chat: showAll + force-mount + seek) rather
55
+ * than scrollTo(−1). Rendering a tick for it is still correct — the
56
+ * turn EXISTS and is navigable, it is just folded away right now
57
+ * (drawing only window turns read as "the rail covers just 2-3 nodes"
58
+ * on tool-heavy sessions where 300 rows ≈ a handful of turns).
59
+ */
60
+ folded?: boolean;
61
+ }
62
+ /** The per-commit snapshot MessageList reports and the rail + sticky
63
+ * header consume — one source so the two can never disagree. */
64
+ export interface TimelineSnapshot {
65
+ /** Turns in conversation order. */
66
+ turns: ReadonlyArray<TimelineTurn>;
67
+ /** Turn owning the viewport top row; first turn while pre-turn content
68
+ * owns the top; null only when there are no turns. */
69
+ activeId: number | null;
70
+ /** ▲ target (strictly above the top), null at the first turn. */
71
+ upId: number | null;
72
+ /** ▼ target (below the top and reachable), null at the end. */
73
+ downId: number | null;
74
+ }
75
+ /** Per-render rail geometry: where the ticks and chevrons landed. */
76
+ export interface RailGeometry {
77
+ /** Turn-index window shown as ticks: [windowStart, windowEnd). */
78
+ windowStart: number;
79
+ windowEnd: number;
80
+ /** Row of the ▲ chevron (block-local, within the rail column). */
81
+ upRow: number;
82
+ /** Row of the first tick. */
83
+ tickTop: number;
84
+ /** Row of the ▼ chevron. */
85
+ downRow: number;
86
+ }
87
+ /** What a rail row is. */
88
+ export type RailHit = {
89
+ kind: 'up';
90
+ } | {
91
+ kind: 'down';
92
+ } | {
93
+ kind: 'tick';
94
+ index: number;
95
+ };
96
+ /** Single eligibility policy: setting, terminal width, turn count, and
97
+ * geometric feasibility in one place. */
98
+ export declare function railEligible(opts: {
99
+ turnCount: number;
100
+ terminalWidth: number;
101
+ viewportRows: number;
102
+ /** False when the content fits the viewport (inline mode / fresh
103
+ * session): nothing to navigate, the terminal's own scrollback owns
104
+ * the wheel. */
105
+ scrollable: boolean;
106
+ }): boolean;
107
+ /**
108
+ * Compute rail geometry, or null when the rail must not render.
109
+ *
110
+ * Windowing: when turns outnumber tick rows (viewport − 2 chevrons), slide
111
+ * a window around the ACTIVE turn; at the bottom prefer the tail so the
112
+ * newest ticks stay visible — but never exclude the active turn, or no
113
+ * tick would highlight. The chevron+tick block is vertically centered in
114
+ * the rail column.
115
+ */
116
+ export declare function computeRailGeometry(turnCount: number, viewportRows: number, activeIndex: number | null, atBottom: boolean): RailGeometry | null;
117
+ /**
118
+ * Which rail interaction a block-local row lands on. The whole rail width
119
+ * is the hit target (no pixel-hunting the glyph).
120
+ */
121
+ export declare function railHit(geo: RailGeometry, row: number): RailHit | null;
122
+ /**
123
+ * First non-empty line, char-capped with a `…` marker. Bounded work: the
124
+ * scan stops at the first non-empty line and slices at the cap, so a huge
125
+ * one-line prompt costs O(cap), not O(line length). Char cap (not display
126
+ * width) on purpose — this bounds the stored snapshot; the hover card
127
+ * re-wraps to its own width (wrapPreviewLines).
128
+ */
129
+ export declare function clipPreview(text: string, maxChars?: number): string;
130
+ /**
131
+ * Wrap a preview to at most 2 lines by DISPLAY width (CJK-aware — a
132
+ * terminal cell column budget, not a char count). The last line is
133
+ * ellipsized when content remains. Char-by-char accumulation keeps
134
+ * surrogate pairs and (best-effort) combining sequences intact by never
135
+ * splitting below a low surrogate.
136
+ */
137
+ export declare function wrapPreviewLines(preview: string, maxWidth: number): string[];
138
+ //# sourceMappingURL=timeline-rail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline-rail.d.ts","sourceRoot":"","sources":["../../../src/ink/timeline-rail.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAIH,qDAAqD;AACrD,eAAO,MAAM,UAAU,IAAI,CAAA;AAE3B,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB,KAAK,CAAA;AAEzC,mDAAmD;AACnD,eAAO,MAAM,cAAc,IAAI,CAAA;AAE/B,0EAA0E;AAC1E,eAAO,MAAM,iBAAiB,MAAM,CAAA;AAEpC;uEACuE;AACvE,MAAM,WAAW,YAAY;IAC3B,4DAA4D;IAC5D,EAAE,EAAE,MAAM,CAAA;IACV;6BACyB;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAA;IACf;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED;iEACiE;AACjE,MAAM,WAAW,gBAAgB;IAC/B,mCAAmC;IACnC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,CAAA;IAClC;2DACuD;IACvD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,iEAAiE;IACjE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,+DAA+D;IAC/D,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB;AAED,qEAAqE;AACrE,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAA;IACb,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,0BAA0B;AAC1B,MAAM,MAAM,OAAO,GACf;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,GACd;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAEnC;0CAC0C;AAC1C,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB;;qBAEiB;IACjB,UAAU,EAAE,OAAO,CAAA;CACpB,GAAG,OAAO,CAOV;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,QAAQ,EAAE,OAAO,GAChB,YAAY,GAAG,IAAI,CAuBrB;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAUtE;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAoB,GAAG,MAAM,CAkB9E;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CA+B5E"}
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Timeline rail — the pure geometry model behind the fullscreen
3
+ * transcript's turn navigator (a port of Grok Build's timeline sidebar
4
+ * semantics onto the dsh Ink tree).
5
+ *
6
+ * The rail is a 2-column gutter REPLACING the classic scrollbar: one tick
7
+ * per user turn, where tick position encodes CONVERSATION ORDER, not
8
+ * scroll proportion. Geometry is computed into a single frozen structure
9
+ * consumed by both the renderer and mouse hit-testing, so what you see is
10
+ * always what you can click ("看得到但点不中" impossible by construction).
11
+ *
12
+ * Viewport semantics (all derived from the same turn-top list, mirroring
13
+ * grok-pager's ScrollbackState):
14
+ *
15
+ * - active: the LAST turn whose prompt top is at-or-above the viewport
16
+ * top (the turn whose content owns the top row — "the turn being
17
+ * read"). When pre-turn content (logo / loaded-context panel) owns the
18
+ * top, the FIRST turn stands in. Never the newest-turn clamp: its
19
+ * one-step-off-bottom highlight leap is exactly what this rule avoids.
20
+ * - up target: the last turn STRICTLY above the viewport top. From
21
+ * mid-turn it first aligns the current turn's own prompt, and it can
22
+ * never name a trailing turn no scroll could bring to the top
23
+ * (the stuck-▲ bug).
24
+ * - down target: the FIRST turn whose prompt top is strictly below the
25
+ * viewport top AND reachable (top ≤ maxScroll — the renderer clamps
26
+ * scrollTop to maxScroll, so a turn below it could never own the top
27
+ * row; naming it would make ▼ repeat itself forever).
28
+ *
29
+ * Not ported (deliberately): ratatui Buffer drawing and Rust state
30
+ * organization — algorithms only, per the reference report.
31
+ */
32
+ import { stringWidth } from './stringWidth.js';
33
+ /** Columns the rail reserves (widest tick glyph). */
34
+ export const RAIL_WIDTH = 2;
35
+ /** Terminals narrower than this hide the rail (transcript needs the cols). */
36
+ export const RAIL_MIN_TERMINAL_WIDTH = 60;
37
+ /** Fewer turns than this and the rail is noise. */
38
+ export const RAIL_MIN_TURNS = 2;
39
+ /** Stored preview cap (chars). Render paths re-truncate to card width. */
40
+ export const PREVIEW_MAX_CHARS = 120;
41
+ /** Single eligibility policy: setting, terminal width, turn count, and
42
+ * geometric feasibility in one place. */
43
+ export function railEligible(opts) {
44
+ return (opts.scrollable &&
45
+ opts.turnCount >= RAIL_MIN_TURNS &&
46
+ opts.terminalWidth >= RAIL_MIN_TERMINAL_WIDTH &&
47
+ opts.viewportRows >= 3);
48
+ }
49
+ /**
50
+ * Compute rail geometry, or null when the rail must not render.
51
+ *
52
+ * Windowing: when turns outnumber tick rows (viewport − 2 chevrons), slide
53
+ * a window around the ACTIVE turn; at the bottom prefer the tail so the
54
+ * newest ticks stay visible — but never exclude the active turn, or no
55
+ * tick would highlight. The chevron+tick block is vertically centered in
56
+ * the rail column.
57
+ */
58
+ export function computeRailGeometry(turnCount, viewportRows, activeIndex, atBottom) {
59
+ if (turnCount < RAIL_MIN_TURNS)
60
+ return null;
61
+ const maxTicks = viewportRows - 2;
62
+ if (maxTicks < 1)
63
+ return null;
64
+ let start = 0;
65
+ if (turnCount > maxTicks) {
66
+ const tailStart = turnCount - maxTicks;
67
+ const anchor = activeIndex ?? turnCount - 1;
68
+ start = atBottom
69
+ ? Math.min(anchor, tailStart)
70
+ : Math.min(Math.max(0, anchor - Math.floor(maxTicks / 2)), tailStart);
71
+ }
72
+ const shown = Math.min(turnCount, maxTicks);
73
+ // Vertically center the ▲ + ticks + ▼ stack, like the web rail.
74
+ const blockTop = Math.max(0, Math.floor((viewportRows - (shown + 2)) / 2));
75
+ return {
76
+ windowStart: start,
77
+ windowEnd: start + shown,
78
+ upRow: blockTop,
79
+ tickTop: blockTop + 1,
80
+ downRow: blockTop + 1 + shown,
81
+ };
82
+ }
83
+ /**
84
+ * Which rail interaction a block-local row lands on. The whole rail width
85
+ * is the hit target (no pixel-hunting the glyph).
86
+ */
87
+ export function railHit(geo, row) {
88
+ if (row === geo.upRow)
89
+ return { kind: 'up' };
90
+ if (row === geo.downRow)
91
+ return { kind: 'down' };
92
+ if (row >= geo.tickTop) {
93
+ const rel = row - geo.tickTop;
94
+ if (rel < geo.windowEnd - geo.windowStart) {
95
+ return { kind: 'tick', index: geo.windowStart + rel };
96
+ }
97
+ }
98
+ return null;
99
+ }
100
+ /**
101
+ * First non-empty line, char-capped with a `…` marker. Bounded work: the
102
+ * scan stops at the first non-empty line and slices at the cap, so a huge
103
+ * one-line prompt costs O(cap), not O(line length). Char cap (not display
104
+ * width) on purpose — this bounds the stored snapshot; the hover card
105
+ * re-wraps to its own width (wrapPreviewLines).
106
+ */
107
+ export function clipPreview(text, maxChars = PREVIEW_MAX_CHARS) {
108
+ let line = '';
109
+ let rest = text;
110
+ while (rest.length > 0) {
111
+ const nl = rest.indexOf('\n');
112
+ const head = nl === -1 ? rest : rest.slice(0, nl);
113
+ rest = nl === -1 ? '' : rest.slice(nl + 1);
114
+ const trimmed = head.trim();
115
+ if (trimmed.length > 0) {
116
+ line = trimmed;
117
+ break;
118
+ }
119
+ }
120
+ if (line.length <= maxChars)
121
+ return line;
122
+ // Keep the cap INCLUDING the ellipsis marker, like grok's preview. Slice
123
+ // by CODE POINTS, not UTF-16 units — a surrogate pair split mid-pair
124
+ // would emit a lone surrogate to the terminal.
125
+ return `${[...line].slice(0, maxChars - 1).join('')}…`;
126
+ }
127
+ /**
128
+ * Wrap a preview to at most 2 lines by DISPLAY width (CJK-aware — a
129
+ * terminal cell column budget, not a char count). The last line is
130
+ * ellipsized when content remains. Char-by-char accumulation keeps
131
+ * surrogate pairs and (best-effort) combining sequences intact by never
132
+ * splitting below a low surrogate.
133
+ */
134
+ export function wrapPreviewLines(preview, maxWidth) {
135
+ const widthOf = stringWidth;
136
+ const lines = [];
137
+ let current = '';
138
+ let currentW = 0;
139
+ for (const ch of preview) {
140
+ const w = widthOf(ch);
141
+ if (w <= 0) {
142
+ // Zero-width (combining marks, ZWJ): attach for free.
143
+ current += ch;
144
+ continue;
145
+ }
146
+ if (currentW + w > maxWidth) {
147
+ if (lines.length === 1) {
148
+ // Second line full → ellipsize in place and stop.
149
+ return [lines[0], ellipsize(current, maxWidth)];
150
+ }
151
+ lines.push(current);
152
+ current = ch;
153
+ currentW = w;
154
+ continue;
155
+ }
156
+ current += ch;
157
+ currentW += w;
158
+ }
159
+ if (current.length > 0 || lines.length === 0)
160
+ lines.push(current);
161
+ if (lines.length > 2) {
162
+ // Cannot happen (we stop after the second), kept for exhaustiveness.
163
+ return [lines[0], ellipsize(lines[1], maxWidth)];
164
+ }
165
+ return lines.slice(0, 2);
166
+ }
167
+ function ellipsize(line, maxWidth) {
168
+ // Make room for '…' (1 col) then hard-cut by display width.
169
+ let out = '';
170
+ let w = 0;
171
+ for (const ch of line) {
172
+ const cw = stringWidth(ch);
173
+ if (cw > 0 && w + cw > maxWidth - 1)
174
+ break;
175
+ out += ch;
176
+ w += cw;
177
+ }
178
+ return `${out}…`;
179
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"wrap-text.d.ts","sourceRoot":"","sources":["../../../src/ink/wrap-text.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAqCzC;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAC9B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,GAC3B,MAAM,CA8BR"}
1
+ {"version":3,"file":"wrap-text.d.ts","sourceRoot":"","sources":["../../../src/ink/wrap-text.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAoFzC;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAC9B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,GAC3B,MAAM,CAoCR"}