@deepseek-harness-tui/dsh-tui 0.8.7 → 0.9.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 (229) hide show
  1. package/README.md +29 -10
  2. package/bin/dsh-tui.js +1 -1
  3. package/lib/types/commands.d.ts.map +1 -1
  4. package/lib/types/commands.js +4 -2
  5. package/lib/types/components/ActivityPicker.d.ts +4 -1
  6. package/lib/types/components/ActivityPicker.d.ts.map +1 -1
  7. package/lib/types/components/ActivityPicker.js +2 -2
  8. package/lib/types/components/BtwPanel.d.ts.map +1 -1
  9. package/lib/types/components/BtwPanel.js +1 -1
  10. package/lib/types/components/Chat/SubagentMessage.d.ts +2 -1
  11. package/lib/types/components/Chat/SubagentMessage.d.ts.map +1 -1
  12. package/lib/types/components/Chat/SubagentMessage.js +11 -3
  13. package/lib/types/components/CommandSuggestions.d.ts +21 -4
  14. package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
  15. package/lib/types/components/CommandSuggestions.js +41 -14
  16. package/lib/types/components/EffortSlider.d.ts +4 -1
  17. package/lib/types/components/EffortSlider.d.ts.map +1 -1
  18. package/lib/types/components/EffortSlider.js +4 -2
  19. package/lib/types/components/ExtensionDialog.js +6 -2
  20. package/lib/types/components/FileSuggestions.d.ts +26 -5
  21. package/lib/types/components/FileSuggestions.d.ts.map +1 -1
  22. package/lib/types/components/FileSuggestions.js +53 -16
  23. package/lib/types/components/GoalTodoPanel.d.ts +26 -2
  24. package/lib/types/components/GoalTodoPanel.d.ts.map +1 -1
  25. package/lib/types/components/GoalTodoPanel.js +86 -17
  26. package/lib/types/components/HelpMenu.d.ts +7 -1
  27. package/lib/types/components/HelpMenu.d.ts.map +1 -1
  28. package/lib/types/components/HelpMenu.js +12 -4
  29. package/lib/types/components/HistorySearchDialog.d.ts +4 -1
  30. package/lib/types/components/HistorySearchDialog.d.ts.map +1 -1
  31. package/lib/types/components/HistorySearchDialog.js +2 -2
  32. package/lib/types/components/LangPicker.d.ts +14 -0
  33. package/lib/types/components/LangPicker.d.ts.map +1 -0
  34. package/lib/types/components/LangPicker.js +17 -0
  35. package/lib/types/components/LoadedContextPanel.d.ts.map +1 -1
  36. package/lib/types/components/LoadedContextPanel.js +3 -1
  37. package/lib/types/components/LogoV2.d.ts +5 -1
  38. package/lib/types/components/LogoV2.d.ts.map +1 -1
  39. package/lib/types/components/LogoV2.js +12 -3
  40. package/lib/types/components/Markdown.d.ts.map +1 -1
  41. package/lib/types/components/Markdown.js +12 -3
  42. package/lib/types/components/MessageList.d.ts +43 -2
  43. package/lib/types/components/MessageList.d.ts.map +1 -1
  44. package/lib/types/components/MessageList.js +553 -41
  45. package/lib/types/components/ModelPicker.d.ts +4 -1
  46. package/lib/types/components/ModelPicker.d.ts.map +1 -1
  47. package/lib/types/components/ModelPicker.js +2 -2
  48. package/lib/types/components/PermissionsPicker.d.ts +21 -0
  49. package/lib/types/components/PermissionsPicker.d.ts.map +1 -0
  50. package/lib/types/components/PermissionsPicker.js +27 -0
  51. package/lib/types/components/PlanPicker.d.ts +15 -0
  52. package/lib/types/components/PlanPicker.d.ts.map +1 -0
  53. package/lib/types/components/PlanPicker.js +18 -0
  54. package/lib/types/components/PresetPicker.d.ts +4 -1
  55. package/lib/types/components/PresetPicker.d.ts.map +1 -1
  56. package/lib/types/components/PresetPicker.js +2 -2
  57. package/lib/types/components/PromptInput.d.ts +4 -3
  58. package/lib/types/components/PromptInput.d.ts.map +1 -1
  59. package/lib/types/components/PromptInput.js +273 -50
  60. package/lib/types/components/RewindPicker.d.ts +12 -1
  61. package/lib/types/components/RewindPicker.d.ts.map +1 -1
  62. package/lib/types/components/RewindPicker.js +6 -4
  63. package/lib/types/components/ScrollbarGutter.d.ts +28 -0
  64. package/lib/types/components/ScrollbarGutter.d.ts.map +1 -0
  65. package/lib/types/components/ScrollbarGutter.js +68 -0
  66. package/lib/types/components/Select.d.ts +8 -1
  67. package/lib/types/components/Select.d.ts.map +1 -1
  68. package/lib/types/components/Select.js +4 -2
  69. package/lib/types/components/SkillsPicker.d.ts +4 -1
  70. package/lib/types/components/SkillsPicker.d.ts.map +1 -1
  71. package/lib/types/components/SkillsPicker.js +2 -2
  72. package/lib/types/components/SubagentCard.d.ts +2 -1
  73. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  74. package/lib/types/components/SubagentCard.js +6 -1
  75. package/lib/types/components/SubagentDashboard.d.ts +4 -0
  76. package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
  77. package/lib/types/components/SubagentDashboard.js +9 -1
  78. package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
  79. package/lib/types/components/SubagentDetailScene.js +5 -4
  80. package/lib/types/components/SuggestionCard.d.ts +63 -0
  81. package/lib/types/components/SuggestionCard.d.ts.map +1 -0
  82. package/lib/types/components/SuggestionCard.js +77 -0
  83. package/lib/types/components/ThemePicker.d.ts +4 -1
  84. package/lib/types/components/ThemePicker.d.ts.map +1 -1
  85. package/lib/types/components/ThemePicker.js +2 -2
  86. package/lib/types/components/ThinkingToggle.d.ts +4 -1
  87. package/lib/types/components/ThinkingToggle.d.ts.map +1 -1
  88. package/lib/types/components/ThinkingToggle.js +2 -2
  89. package/lib/types/components/TimelineRail.d.ts +53 -0
  90. package/lib/types/components/TimelineRail.d.ts.map +1 -0
  91. package/lib/types/components/TimelineRail.js +190 -0
  92. package/lib/types/components/WorkspaceFlowPicker.d.ts +6 -1
  93. package/lib/types/components/WorkspaceFlowPicker.d.ts.map +1 -1
  94. package/lib/types/components/WorkspaceFlowPicker.js +4 -2
  95. package/lib/types/components/WorkspaceMenuPicker.d.ts +19 -0
  96. package/lib/types/components/WorkspaceMenuPicker.d.ts.map +1 -0
  97. package/lib/types/components/WorkspaceMenuPicker.js +19 -0
  98. package/lib/types/components/WorkspacePicker.d.ts +4 -1
  99. package/lib/types/components/WorkspacePicker.d.ts.map +1 -1
  100. package/lib/types/components/WorkspacePicker.js +2 -2
  101. package/lib/types/components/approvals/ApprovalPanel.d.ts.map +1 -1
  102. package/lib/types/components/approvals/ApprovalPanel.js +5 -1
  103. package/lib/types/components/design-system/ListItem.d.ts +8 -1
  104. package/lib/types/components/design-system/ListItem.d.ts.map +1 -1
  105. package/lib/types/components/design-system/ListItem.js +8 -3
  106. package/lib/types/components/messages/AssistantTextMessage.d.ts +5 -2
  107. package/lib/types/components/messages/AssistantTextMessage.d.ts.map +1 -1
  108. package/lib/types/components/messages/AssistantTextMessage.js +6 -2
  109. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +2 -1
  110. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  111. package/lib/types/components/messages/AssistantThinkingMessage.js +10 -4
  112. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +8 -1
  113. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  114. package/lib/types/components/messages/AssistantToolUseMessage.js +4 -2
  115. package/lib/types/components/messages/UserPromptMessage.d.ts +2 -1
  116. package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
  117. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  118. package/lib/types/components/questions/AskUserQuestionPanel.js +34 -2
  119. package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
  120. package/lib/types/components/questions/PlanReviewPanel.js +13 -2
  121. package/lib/types/components/sessions/SessionListRow.d.ts +4 -1
  122. package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
  123. package/lib/types/components/sessions/SessionListRow.js +4 -2
  124. package/lib/types/components/trajectory/HotspotView.d.ts +7 -1
  125. package/lib/types/components/trajectory/HotspotView.d.ts.map +1 -1
  126. package/lib/types/components/trajectory/HotspotView.js +8 -2
  127. package/lib/types/components/trajectory/Ledger.d.ts +9 -1
  128. package/lib/types/components/trajectory/Ledger.d.ts.map +1 -1
  129. package/lib/types/components/trajectory/Ledger.js +23 -5
  130. package/lib/types/components/trajectory/WaveBand.d.ts +10 -1
  131. package/lib/types/components/trajectory/WaveBand.d.ts.map +1 -1
  132. package/lib/types/components/trajectory/WaveBand.js +7 -2
  133. package/lib/types/dsh-adapter/channel.d.ts +27 -6
  134. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  135. package/lib/types/dsh-adapter/channel.js +432 -66
  136. package/lib/types/dsh-adapter/contract.d.ts +58 -18
  137. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  138. package/lib/types/dsh-adapter/contract.js +124 -36
  139. package/lib/types/dsh-adapter/index.d.ts +10 -2
  140. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  141. package/lib/types/dsh-adapter/index.js +10 -13
  142. package/lib/types/dsh-adapter/plugin.d.ts +0 -9
  143. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  144. package/lib/types/dsh-adapter/plugin.js +136 -6
  145. package/lib/types/i18n.d.ts +194 -16
  146. package/lib/types/i18n.d.ts.map +1 -1
  147. package/lib/types/i18n.js +73 -10
  148. package/lib/types/ink/components/AlternateScreen.d.ts.map +1 -1
  149. package/lib/types/ink/components/AlternateScreen.js +13 -1
  150. package/lib/types/ink/components/App.d.ts +12 -1
  151. package/lib/types/ink/components/App.d.ts.map +1 -1
  152. package/lib/types/ink/components/App.js +101 -4
  153. package/lib/types/ink/components/ClockContext.d.ts.map +1 -1
  154. package/lib/types/ink/components/ClockContext.js +2 -0
  155. package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
  156. package/lib/types/ink/components/ScrollBox.js +170 -91
  157. package/lib/types/ink/constants.d.ts +9 -0
  158. package/lib/types/ink/constants.d.ts.map +1 -1
  159. package/lib/types/ink/constants.js +9 -0
  160. package/lib/types/ink/events/click-event.d.ts +7 -16
  161. package/lib/types/ink/events/click-event.d.ts.map +1 -1
  162. package/lib/types/ink/events/click-event.js +16 -19
  163. package/lib/types/ink/events/event-handlers.d.ts +11 -1
  164. package/lib/types/ink/events/event-handlers.d.ts.map +1 -1
  165. package/lib/types/ink/events/event-handlers.js +2 -0
  166. package/lib/types/ink/events/input-event.d.ts +9 -0
  167. package/lib/types/ink/events/input-event.d.ts.map +1 -1
  168. package/lib/types/ink/events/input-event.js +4 -0
  169. package/lib/types/ink/events/pointer-event.d.ts +61 -0
  170. package/lib/types/ink/events/pointer-event.d.ts.map +1 -0
  171. package/lib/types/ink/events/pointer-event.js +61 -0
  172. package/lib/types/ink/events/wheel-event.d.ts +17 -0
  173. package/lib/types/ink/events/wheel-event.d.ts.map +1 -0
  174. package/lib/types/ink/events/wheel-event.js +20 -0
  175. package/lib/types/ink/geometry-trace.d.ts +51 -0
  176. package/lib/types/ink/geometry-trace.d.ts.map +1 -0
  177. package/lib/types/ink/geometry-trace.js +83 -0
  178. package/lib/types/ink/hit-test.d.ts +56 -1
  179. package/lib/types/ink/hit-test.d.ts.map +1 -1
  180. package/lib/types/ink/hit-test.js +146 -8
  181. package/lib/types/ink/ink.d.ts +58 -1
  182. package/lib/types/ink/ink.d.ts.map +1 -1
  183. package/lib/types/ink/ink.js +268 -52
  184. package/lib/types/ink/node-cache.d.ts +5 -0
  185. package/lib/types/ink/node-cache.d.ts.map +1 -1
  186. package/lib/types/ink/parse-keypress.d.ts +8 -0
  187. package/lib/types/ink/parse-keypress.d.ts.map +1 -1
  188. package/lib/types/ink/parse-keypress.js +101 -12
  189. package/lib/types/ink/render-node-to-output.d.ts +16 -3
  190. package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
  191. package/lib/types/ink/render-node-to-output.js +144 -25
  192. package/lib/types/ink/selection.d.ts +29 -4
  193. package/lib/types/ink/selection.d.ts.map +1 -1
  194. package/lib/types/ink/selection.js +41 -5
  195. package/lib/types/ink/timeline-rail.d.ts +138 -0
  196. package/lib/types/ink/timeline-rail.d.ts.map +1 -0
  197. package/lib/types/ink/timeline-rail.js +179 -0
  198. package/lib/types/ink/wrap-text.d.ts.map +1 -1
  199. package/lib/types/ink/wrap-text.js +47 -5
  200. package/lib/types/screens/Chat.d.ts.map +1 -1
  201. package/lib/types/screens/Chat.js +819 -337
  202. package/lib/types/screens/SessionBrowser.d.ts.map +1 -1
  203. package/lib/types/screens/SessionBrowser.js +56 -29
  204. package/lib/types/screens/Settings.d.ts.map +1 -1
  205. package/lib/types/screens/Settings.js +64 -22
  206. package/lib/types/screens/StatusLine.d.ts +2 -1
  207. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  208. package/lib/types/screens/StatusLine.js +17 -1
  209. package/lib/types/screens/TrajectoryScene.d.ts.map +1 -1
  210. package/lib/types/screens/TrajectoryScene.js +81 -14
  211. package/lib/types/screens/chatOverlay.d.ts +221 -0
  212. package/lib/types/screens/chatOverlay.d.ts.map +1 -0
  213. package/lib/types/screens/chatOverlay.js +114 -0
  214. package/lib/types/tips.d.ts.map +1 -1
  215. package/lib/types/tips.js +64 -10
  216. package/lib/types/tuiDisplayPrefs.d.ts +15 -0
  217. package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
  218. package/lib/types/tuiDisplayPrefs.js +9 -0
  219. package/lib/types/utils/debug.d.ts +10 -0
  220. package/lib/types/utils/debug.d.ts.map +1 -1
  221. package/lib/types/utils/debug.js +24 -0
  222. package/lib/types/utils/fileSuggestions.d.ts +19 -0
  223. package/lib/types/utils/fileSuggestions.d.ts.map +1 -0
  224. package/lib/types/utils/fileSuggestions.js +40 -0
  225. package/lib/types/utils/mentions.d.ts.map +1 -1
  226. package/lib/types/utils/mentions.js +3 -1
  227. package/lib/types/utils/paths.d.ts.map +1 -1
  228. package/lib/types/utils/paths.js +1 -0
  229. package/package.json +69 -66
@@ -1 +1 @@
1
- {"version":3,"file":"AskUserQuestionPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/questions/AskUserQuestionPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AASvE,MAAM,MAAM,yBAAyB,GAAG;IACtC,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE;QACjB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;QACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;YAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;QAC3F,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAA;QAC9B;;oEAE4D;QAC5D,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAA;QAClC;0EACkE;QAClE,QAAQ,CAAC,MAAM,CAAC,EAAE;YAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;YAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAA;KAC7E,CAAA;IACD,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,sDAAsD;IACtD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,iBAAiB,KAAK,IAAI,CAAA;IACzD,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;CAC9B,CAAA;AAED,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,QAAQ,GACT,EAAE,yBAAyB,GAAG,KAAK,CAAC,SAAS,CAwW7C"}
1
+ {"version":3,"file":"AskUserQuestionPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/questions/AskUserQuestionPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AASvE,MAAM,MAAM,yBAAyB,GAAG;IACtC,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE;QACjB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;QACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;YAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;QAC3F,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAA;QAC9B;;oEAE4D;QAC5D,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAA;QAClC;0EACkE;QAClE,QAAQ,CAAC,MAAM,CAAC,EAAE;YAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;YAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAA;KAC7E,CAAA;IACD,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,sDAAsD;IACtD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,iBAAiB,KAAK,IAAI,CAAA;IACzD,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;CAC9B,CAAA;AAED,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,QAAQ,GACT,EAAE,yBAAyB,GAAG,KAAK,CAAC,SAAS,CA+Y7C"}
@@ -241,7 +241,39 @@ export function AskUserQuestionPanel({ question, position, total, answered, onAn
241
241
  const remaining = total - answered;
242
242
  const headerTitle = ` ${t('question-header-progress', { position, total, remaining: remaining > 1 ? t('question-remaining-more', { n: remaining }) : '' })} `;
243
243
  const cursorChar = customCursor < customText.length ? customText[customCursor] : ' ';
244
- const renderInputRow = () => (_jsxs(Box, { flexDirection: "row", marginTop: inputFocused ? 1 : 0, children: [_jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: inputFocused ? 'claude' : undefined, bold: inputFocused, children: inputFocused ? POINTER : ' ' }) }), _jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: inputFocused ? 'claude' : 'suggestion', children: PENCIL }) }), _jsxs(Box, { flexDirection: "row", marginLeft: 1, children: [_jsx(Text, { bold: inputFocused, color: inputFocused ? 'claude' : 'suggestion', children: t('question-custom-tab') }), attached !== null && (_jsx(Text, { color: "suggestion", children: t('question-attached-label', { label: attached }) })), _jsx(Text, { dimColor: true, children: "\uFF1A" }), customText === '' && !inputFocused ? (_jsx(Text, { ref: caretRef, dimColor: true, children: t('question-direct-input') })) : (_jsxs(_Fragment, { children: [_jsx(Text, { wrap: "wrap", children: customText.slice(0, customCursor) }), inputFocused
244
+ /** Mouse: click the input row to focus it (same as Tab). */
245
+ const focusInputRow = () => {
246
+ if (hideCustomInput)
247
+ return;
248
+ setFocusIndex(options.length);
249
+ setError(null);
250
+ };
251
+ /**
252
+ * Mouse: click an option row. Multi-select toggles the checkmark (same as
253
+ * Space); single-select answers immediately with that option plus any
254
+ * typed text (same as focusing the row and pressing Enter) — one click =
255
+ * one answer, matching ApprovalPanel's click semantics.
256
+ */
257
+ const clickOption = (index) => {
258
+ if (multiSelect) {
259
+ setChecked(previous => {
260
+ const next = new Set(previous);
261
+ if (next.has(index))
262
+ next.delete(index);
263
+ else
264
+ next.add(index);
265
+ return next;
266
+ });
267
+ return;
268
+ }
269
+ const label = options[index]?.label;
270
+ if (label === undefined)
271
+ return;
272
+ const text = customText.trim();
273
+ onAnswer({ selected: [label], ...(text !== '' ? { custom: text } : {}) });
274
+ };
275
+ const [hoverIndex, setHoverIndex] = React.useState(-1);
276
+ const renderInputRow = () => (_jsxs(Box, { flexDirection: "row", marginTop: inputFocused ? 1 : 0, onClick: focusInputRow, onMouseEnter: () => setHoverIndex(options.length), onMouseLeave: () => setHoverIndex(current => (current === options.length ? -1 : current)), backgroundColor: hoverIndex === options.length && !inputFocused ? 'userMessageBackgroundHover' : undefined, children: [_jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: inputFocused ? 'claude' : undefined, bold: inputFocused, children: inputFocused ? POINTER : ' ' }) }), _jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: inputFocused ? 'claude' : 'suggestion', children: PENCIL }) }), _jsxs(Box, { flexDirection: "row", marginLeft: 1, children: [_jsx(Text, { bold: inputFocused, color: inputFocused ? 'claude' : 'suggestion', children: t('question-custom-tab') }), attached !== null && (_jsx(Text, { color: "suggestion", children: t('question-attached-label', { label: attached }) })), _jsx(Text, { dimColor: true, children: "\uFF1A" }), customText === '' && !inputFocused ? (_jsx(Text, { ref: caretRef, dimColor: true, children: t('question-direct-input') })) : (_jsxs(_Fragment, { children: [_jsx(Text, { wrap: "wrap", children: customText.slice(0, customCursor) }), inputFocused
245
277
  ? _jsx(Text, { ref: caretRef, inverse: true, children: cursorChar })
246
278
  : _jsx(Text, { ref: caretRef, color: "suggestion", children: "\u258F" }), _jsx(Text, { wrap: "wrap", children: customText.slice(inputFocused ? customCursor + 1 : customCursor) })] }))] })] }));
247
279
  const renderOptions = () => (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [options.slice(optionWindow.start, optionWindow.end).map((option, index) => {
@@ -259,7 +291,7 @@ export function AskUserQuestionPanel({ question, position, total, answered, onAn
259
291
  const description = windowedOptions
260
292
  ? option.description?.replace(/\s+/gu, ' ').trim()
261
293
  : option.description;
262
- return (_jsxs(Box, { flexDirection: "row", marginTop: !windowedOptions && focused ? 1 : 0, children: [_jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: focused ? 'claude' : undefined, bold: focused, children: pointer }) }), _jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: focused ? 'claude' : undefined, bold: selected, children: selected ? (multiSelect ? CHECKED : '●') : UNCHECKED }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 1, children: [_jsx(Text, { bold: focused || selected, color: focused ? 'claude' : undefined, wrap: windowedOptions ? 'truncate' : 'wrap', children: label }), description !== undefined && (_jsx(Text, { dimColor: true, wrap: windowedOptions ? 'truncate' : 'wrap', children: description }))] })] }, `${absoluteIndex}:${option.label}`));
294
+ return (_jsxs(Box, { flexDirection: "row", marginTop: !windowedOptions && focused ? 1 : 0, onClick: () => clickOption(absoluteIndex), onMouseEnter: () => setHoverIndex(absoluteIndex), onMouseLeave: () => setHoverIndex(current => (current === absoluteIndex ? -1 : current)), backgroundColor: hoverIndex === absoluteIndex && !focused ? 'userMessageBackgroundHover' : undefined, children: [_jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: focused ? 'claude' : undefined, bold: focused, children: pointer }) }), _jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: focused ? 'claude' : undefined, bold: selected, children: selected ? (multiSelect ? CHECKED : '●') : UNCHECKED }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 1, children: [_jsx(Text, { bold: focused || selected, color: focused ? 'claude' : undefined, wrap: windowedOptions ? 'truncate' : 'wrap', children: label }), description !== undefined && (_jsx(Text, { dimColor: true, wrap: windowedOptions ? 'truncate' : 'wrap', children: description }))] })] }, `${absoluteIndex}:${option.label}`));
263
295
  }), hideCustomInput ? null : renderInputRow()] }));
264
296
  const hintParts = inputFocused
265
297
  ? [
@@ -1 +1 @@
1
- {"version":3,"file":"PlanReviewPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/questions/PlanReviewPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAKvE,MAAM,MAAM,oBAAoB,GAAG;IACjC,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE;QACjB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;QACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;YAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;QAC3F,QAAQ,CAAC,MAAM,CAAC,EAAE;YAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;YAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAA;KAC7E,CAAA;IACD,QAAQ,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,iBAAiB,KAAK,IAAI,CAAA;IACzD,iEAAiE;IACjE,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;CAC9B,CAAA;AAED,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,QAAQ,EACR,QAAQ,GACT,EAAE,oBAAoB,GAAG,KAAK,CAAC,SAAS,CAyOxC"}
1
+ {"version":3,"file":"PlanReviewPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/questions/PlanReviewPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAKvE,MAAM,MAAM,oBAAoB,GAAG;IACjC,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE;QACjB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;QACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;YAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;QAC3F,QAAQ,CAAC,MAAM,CAAC,EAAE;YAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;YAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAA;KAC7E,CAAA;IACD,QAAQ,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,iBAAiB,KAAK,IAAI,CAAA;IACzD,iEAAiE;IACjE,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;CAC9B,CAAA;AAED,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,QAAQ,EACR,QAAQ,GACT,EAAE,oBAAoB,GAAG,KAAK,CAAC,SAAS,CAmQxC"}
@@ -168,11 +168,22 @@ export function PlanReviewPanel({ question, onAnswer, onCancel, }) {
168
168
  }
169
169
  }, { isActive: true });
170
170
  const cursorChar = cursor < feedback.length ? feedback[cursor] : ' ';
171
+ /** Mouse: click a decision row = focus it + submit (same as Enter). */
172
+ const [hoverIndex, setHoverIndex] = React.useState(-1);
173
+ const clickOption = (index) => {
174
+ setFocusIndex(index);
175
+ submitOption(index);
176
+ };
177
+ /** Mouse: click the feedback row to focus it. */
178
+ const focusFeedbackRow = () => {
179
+ setFocusIndex(options.length);
180
+ setError(null);
181
+ };
171
182
  return (_jsxs(Box, { flexDirection: "column", marginTop: 1, paddingLeft: 2, paddingRight: 2, width: "100%", children: [_jsx(Divider, { color: "permission", title: ` ${question.header ?? t('plan-review-fallback-header')} `, padding: 4 }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { bold: true, wrap: "wrap", children: question.question }), question.detail !== undefined && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(Markdown, { children: question.detail }) }))] }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [options.map((option, index) => {
172
183
  const focused = index === focusIndex;
173
184
  const isApprove = option.label === approveLabel;
174
- return (_jsxs(Box, { flexDirection: "row", marginTop: focused ? 1 : 0, children: [_jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: focused ? 'claude' : undefined, bold: focused, children: focused ? POINTER : ' ' }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 1, children: [_jsxs(Text, { bold: focused, color: focused || isApprove ? 'claude' : undefined, wrap: "wrap", children: [index + 1, ". ", option.label] }), option.description !== undefined && (_jsx(Text, { dimColor: true, wrap: "wrap", children: option.description }))] })] }, option.label));
175
- }), _jsxs(Box, { flexDirection: "row", marginTop: inputFocused ? 1 : 0, children: [_jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: inputFocused ? 'claude' : undefined, bold: inputFocused, children: inputFocused ? POINTER : ' ' }) }), _jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: inputFocused ? 'claude' : 'suggestion', children: PENCIL }) }), _jsx(Box, { flexDirection: "row", marginLeft: 1, children: feedback === '' && !inputFocused ? (_jsx(Text, { ref: caretRef, dimColor: true, children: t('plan-review-feedback-placeholder') })) : (_jsxs(_Fragment, { children: [_jsx(Text, { wrap: "wrap", children: feedback.slice(0, cursor) }), inputFocused
185
+ return (_jsxs(Box, { flexDirection: "row", marginTop: focused ? 1 : 0, onClick: () => clickOption(index), onMouseEnter: () => setHoverIndex(index), onMouseLeave: () => setHoverIndex(current => (current === index ? -1 : current)), backgroundColor: hoverIndex === index && !focused ? 'userMessageBackgroundHover' : undefined, children: [_jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: focused ? 'claude' : undefined, bold: focused, children: focused ? POINTER : ' ' }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 1, children: [_jsxs(Text, { bold: focused, color: focused || isApprove ? 'claude' : undefined, wrap: "wrap", children: [index + 1, ". ", option.label] }), option.description !== undefined && (_jsx(Text, { dimColor: true, wrap: "wrap", children: option.description }))] })] }, option.label));
186
+ }), _jsxs(Box, { flexDirection: "row", marginTop: inputFocused ? 1 : 0, onClick: focusFeedbackRow, onMouseEnter: () => setHoverIndex(options.length), onMouseLeave: () => setHoverIndex(current => (current === options.length ? -1 : current)), backgroundColor: hoverIndex === options.length && !inputFocused ? 'userMessageBackgroundHover' : undefined, children: [_jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: inputFocused ? 'claude' : undefined, bold: inputFocused, children: inputFocused ? POINTER : ' ' }) }), _jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: inputFocused ? 'claude' : 'suggestion', children: PENCIL }) }), _jsx(Box, { flexDirection: "row", marginLeft: 1, children: feedback === '' && !inputFocused ? (_jsx(Text, { ref: caretRef, dimColor: true, children: t('plan-review-feedback-placeholder') })) : (_jsxs(_Fragment, { children: [_jsx(Text, { wrap: "wrap", children: feedback.slice(0, cursor) }), inputFocused
176
187
  ? _jsx(Text, { ref: caretRef, inverse: true, children: cursorChar })
177
188
  : _jsx(Text, { ref: caretRef, color: "suggestion", children: "\u258F" }), _jsx(Text, { wrap: "wrap", children: feedback.slice(inputFocused ? cursor + 1 : cursor) })] })) })] })] }), error !== null && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "error", children: error }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: t('plan-review-hint') }) })] }));
178
189
  }
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import type { ClickEvent } from '../../ink/events/click-event.js';
2
3
  import type { SessionSummary } from '../../dsh-adapter/sessions/index.js';
3
4
  /**
4
5
  * One session in the browser's list: a title line and a metadata line.
@@ -13,7 +14,7 @@ import type { SessionSummary } from '../../dsh-adapter/sessions/index.js';
13
14
  * stay exactly two lines at every terminal width, and a row that wraps
14
15
  * destroys the alignment that lets the eye scan a list at all.
15
16
  */
16
- export declare function SessionListRow({ session, width, depth, focused, now, }: {
17
+ export declare function SessionListRow({ session, width, depth, focused, now, onClick, }: {
17
18
  session: SessionSummary;
18
19
  /** Columns available to the row, indentation included. */
19
20
  width: number;
@@ -22,5 +23,7 @@ export declare function SessionListRow({ session, width, depth, focused, now, }:
22
23
  focused: boolean;
23
24
  /** Epoch ms used for every relative time in this render pass. */
24
25
  now: number;
26
+ /** 鼠标点击行(fullscreen):恢复该会话(与 Enter 同路径)。 */
27
+ onClick?(event: ClickEvent): void;
25
28
  }): React.ReactNode;
26
29
  //# sourceMappingURL=SessionListRow.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SessionListRow.d.ts","sourceRoot":"","sources":["../../../../src/components/sessions/SessionListRow.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAUzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAA;AAEzE;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,KAAK,EACL,KAAK,EACL,OAAO,EACP,GAAG,GACJ,EAAE;IACD,OAAO,EAAE,cAAc,CAAA;IACvB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAA;IACb,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,iEAAiE;IACjE,GAAG,EAAE,MAAM,CAAA;CACZ,GAAG,KAAK,CAAC,SAAS,CAoClB"}
1
+ {"version":3,"file":"SessionListRow.d.ts","sourceRoot":"","sources":["../../../../src/components/sessions/SessionListRow.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAGvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAQjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAA;AAEzE;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,KAAK,EACL,KAAK,EACL,OAAO,EACP,GAAG,EACH,OAAO,GACR,EAAE;IACD,OAAO,EAAE,cAAc,CAAA;IACvB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAA;IACb,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,iEAAiE;IACjE,GAAG,EAAE,MAAM,CAAA;IACX,4CAA4C;IAC5C,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;CAClC,GAAG,KAAK,CAAC,SAAS,CA4ClB"}
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
2
3
  import { Box, Text } from '../../ui.js';
3
4
  import { t } from '../../i18n.js';
4
5
  import { formatBytes, formatWhen, kindMark, titleColor, truncateWidth, } from '../../sessions/format.js';
@@ -15,11 +16,12 @@ import { formatBytes, formatWhen, kindMark, titleColor, truncateWidth, } from '.
15
16
  * stay exactly two lines at every terminal width, and a row that wraps
16
17
  * destroys the alignment that lets the eye scan a list at all.
17
18
  */
18
- export function SessionListRow({ session, width, depth, focused, now, }) {
19
+ export function SessionListRow({ session, width, depth, focused, now, onClick, }) {
19
20
  const indent = depth * 2;
20
21
  // Two cells for the focus marker, plus the indent for a nested run.
21
22
  const body = Math.max(8, width - 2 - indent);
22
23
  const mark = kindMark(session.kind);
24
+ const [hovered, setHovered] = useState(false);
23
25
  const facts = [formatWhen(session.updatedAt, now)];
24
26
  if (session.branch !== undefined)
25
27
  facts.push(session.branch);
@@ -31,5 +33,5 @@ export function SessionListRow({ session, width, depth, focused, now, }) {
31
33
  if (session.childCount > 0 && depth === 0) {
32
34
  facts.push(t('session-children', { n: session.childCount }));
33
35
  }
34
- return (_jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [_jsxs(Box, { children: [_jsx(Text, { color: focused ? 'suggestion' : 'subtle', children: `${' '.repeat(indent)}${focused ? '❯ ' : ' '}` }), mark !== undefined && _jsx(Text, { color: mark.color, children: `${mark.glyph} ` }), _jsx(Text, { color: titleColor(session.title.source, focused), bold: focused, children: truncateWidth(session.label ?? session.title.text, body - (mark === undefined ? 0 : 2)) })] }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: `${' '.repeat(indent + 2)}${truncateWidth(facts.join(' · '), body)}` }) })] }));
36
+ return (_jsxs(Box, { flexDirection: "column", flexShrink: 0, onClick: onClick, onMouseEnter: onClick !== undefined ? () => setHovered(true) : undefined, onMouseLeave: onClick !== undefined ? () => setHovered(false) : undefined, backgroundColor: hovered && !focused ? 'userMessageBackgroundHover' : undefined, children: [_jsxs(Box, { children: [_jsx(Text, { color: focused ? 'suggestion' : 'subtle', children: `${' '.repeat(indent)}${focused ? '❯ ' : ' '}` }), mark !== undefined && _jsx(Text, { color: mark.color, children: `${mark.glyph} ` }), _jsx(Text, { color: titleColor(session.title.source, focused), bold: focused, children: truncateWidth(session.label ?? session.title.text, body - (mark === undefined ? 0 : 2)) })] }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: `${' '.repeat(indent + 2)}${truncateWidth(facts.join(' · '), body)}` }) })] }));
35
37
  }
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import type { HotspotRow, HotspotSort, TrajAggregate } from '../../dsh-adapter/types.js';
3
3
  /** Flatten the three sections into the single list the cursor walks. */
4
4
  export declare function hotspotRows(agg: TrajAggregate): HotspotRow[];
5
- export declare function HotspotView({ agg, sort, width, height, cursor, tick, switchTick, }: {
5
+ export declare function HotspotView({ agg, sort, width, height, cursor, tick, switchTick, onRowClick, }: {
6
6
  agg: TrajAggregate;
7
7
  sort: HotspotSort;
8
8
  width: number;
@@ -10,5 +10,11 @@ export declare function HotspotView({ agg, sort, width, height, cursor, tick, sw
10
10
  cursor: number;
11
11
  tick: number;
12
12
  switchTick: number;
13
+ /**
14
+ * Mouse pick (fullscreen): reports the clicked row's cursor index — the
15
+ * scene jumps back to the timeline positioned on the group's first member
16
+ * (same path as the keyboard Enter). Hover shows a dim `▸` pointer.
17
+ */
18
+ onRowClick?: (cursorIndex: number) => void;
13
19
  }): React.ReactNode;
14
20
  //# sourceMappingURL=HotspotView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"HotspotView.d.ts","sourceRoot":"","sources":["../../../../src/components/trajectory/HotspotView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AA6CxF,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,UAAU,EAAE,CAE5D;AAOD,wBAAgB,WAAW,CAAC,EAC1B,GAAG,EACH,IAAI,EACJ,KAAK,EACL,MAAM,EACN,MAAM,EACN,IAAI,EACJ,UAAU,GACX,EAAE;IACD,GAAG,EAAE,aAAa,CAAA;IAClB,IAAI,EAAE,WAAW,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;CACnB,GAAG,KAAK,CAAC,SAAS,CA4ElB"}
1
+ {"version":3,"file":"HotspotView.d.ts","sourceRoot":"","sources":["../../../../src/components/trajectory/HotspotView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AA6CxF,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,UAAU,EAAE,CAE5D;AAOD,wBAAgB,WAAW,CAAC,EAC1B,GAAG,EACH,IAAI,EACJ,KAAK,EACL,MAAM,EACN,MAAM,EACN,IAAI,EACJ,UAAU,EACV,UAAU,GACX,EAAE;IACD,GAAG,EAAE,aAAa,CAAA;IAClB,IAAI,EAAE,WAAW,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAA;CAC3C,GAAG,KAAK,CAAC,SAAS,CA6FlB"}
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
2
3
  import { Box, Text, useTheme } from '../../ui.js';
3
4
  import { getTheme } from '../../theme.js';
4
5
  import { formatDuration, formatTokens, truncateWidth } from '../../trajectory/format.js';
@@ -40,9 +41,10 @@ export function hotspotRows(agg) {
40
41
  function valueOf(row, sort) {
41
42
  return sort === 'count' ? row.count : sort === 'tokens' ? row.tokens : row.totalMs;
42
43
  }
43
- export function HotspotView({ agg, sort, width, height, cursor, tick, switchTick, }) {
44
+ export function HotspotView({ agg, sort, width, height, cursor, tick, switchTick, onRowClick, }) {
44
45
  const [themeName] = useTheme();
45
46
  const theme = getTheme(themeName);
47
+ const [hoverIndex, setHoverIndex] = React.useState(-1);
46
48
  const labelWidth = Math.min(18, Math.max(10, Math.floor(width * 0.16)));
47
49
  const barWidth = Math.max(6, Math.min(30, width - labelWidth - 34));
48
50
  // Build the flat list once, tagging each row with its section's scale.
@@ -72,12 +74,16 @@ export function HotspotView({ agg, sort, width, height, cursor, tick, switchTick
72
74
  }
73
75
  const { row, max, colorKey } = entry;
74
76
  const focused = entry.cursorIndex === cursor;
77
+ // 鼠标:行点击跳回 timeline 定位;悬停轻指示(dim ▸,不刷背景)
78
+ const hovered = onRowClick !== undefined && hoverIndex === entry.cursorIndex;
75
79
  // Stagger the settle by row so a section reads top-down on switch.
76
80
  const dim = reproject(tick - offset, switchTick);
77
81
  const base = row.error === true ? theme.error : theme[colorKey];
78
82
  const stats = `${row.count}×` +
79
83
  (row.tokens > 0 ? ` · ${formatTokens(row.tokens)}` : '') +
80
84
  (row.count > 0 && row.totalMs > 0 ? ` · ⌀${formatDuration(row.totalMs / row.count)}` : '');
81
- return (_jsxs(Box, { flexDirection: "row", width: "100%", height: 1, flexShrink: 0, gap: 1, children: [_jsx(Box, { flexShrink: 0, width: 2, children: _jsx(Text, { color: "suggestion", children: focused ? '▸' : ' ' }) }), _jsx(Box, { flexShrink: 0, width: labelWidth, children: _jsx(Text, { color: focused ? 'suggestion' : row.error === true ? 'error' : undefined, children: truncateWidth(row.label, labelWidth) }) }), _jsx(Box, { flexShrink: 0, width: barWidth, children: _jsx(Text, { color: mix(base, theme.background, dim), children: bar(valueOf(row, sort), max, barWidth) }) }), _jsx(Box, { flexShrink: 0, width: 8, justifyContent: "flex-end", children: _jsx(Text, { bold: true, color: row.error === true ? 'error' : undefined, children: formatDuration(row.totalMs) }) }), _jsx(Box, { flexShrink: 1, overflow: "hidden", children: _jsx(Text, { color: "subtle", children: truncateWidth(stats, Math.max(4, width - labelWidth - barWidth - 16)) }) })] }, `r${entry.cursorIndex}`));
85
+ return (_jsxs(Box, { flexDirection: "row", width: "100%", height: 1, flexShrink: 0, gap: 1, onClick: onRowClick === undefined ? undefined : () => onRowClick(entry.cursorIndex), onMouseEnter: onRowClick === undefined ? undefined : () => setHoverIndex(entry.cursorIndex), onMouseLeave: onRowClick === undefined
86
+ ? undefined
87
+ : () => setHoverIndex(previous => (previous === entry.cursorIndex ? -1 : previous)), children: [_jsx(Box, { flexShrink: 0, width: 2, children: _jsx(Text, { color: focused ? 'suggestion' : 'inactive', children: focused || hovered ? '▸' : ' ' }) }), _jsx(Box, { flexShrink: 0, width: labelWidth, children: _jsx(Text, { color: focused ? 'suggestion' : row.error === true ? 'error' : undefined, children: truncateWidth(row.label, labelWidth) }) }), _jsx(Box, { flexShrink: 0, width: barWidth, children: _jsx(Text, { color: mix(base, theme.background, dim), children: bar(valueOf(row, sort), max, barWidth) }) }), _jsx(Box, { flexShrink: 0, width: 8, justifyContent: "flex-end", children: _jsx(Text, { bold: true, color: row.error === true ? 'error' : undefined, children: formatDuration(row.totalMs) }) }), _jsx(Box, { flexShrink: 1, overflow: "hidden", children: _jsx(Text, { color: "subtle", children: truncateWidth(stats, Math.max(4, width - labelWidth - barWidth - 16)) }) })] }, `r${entry.cursorIndex}`));
82
88
  }) }));
83
89
  }
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
+ import type { ClickEvent } from '../../ink/events/click-event.js';
2
3
  import type { TrajNode } from '../../dsh-adapter/types.js';
3
- export declare function Ledger({ rows, start, height, cursor, width, tick, arrivalTick, arrivalFrom, }: {
4
+ export declare function Ledger({ rows, start, height, cursor, width, tick, arrivalTick, arrivalFrom, onRowClick, }: {
4
5
  /** The (possibly filtered) ledger. */
5
6
  rows: readonly TrajNode[];
6
7
  /** Index of the first visible row. */
@@ -16,5 +17,12 @@ export declare function Ledger({ rows, start, height, cursor, width, tick, arriv
16
17
  arrivalTick: number;
17
18
  /** Rows at or after this index are the ones that just arrived. */
18
19
  arrivalFrom: number;
20
+ /**
21
+ * Mouse pick (fullscreen): reports the clicked row's absolute index — the
22
+ * scene jumps the cursor to it (same semantics as the keyboard jumps).
23
+ * Hover on a non-focused row shows a dim `▸` pointer — light indication,
24
+ * no background wash (the ledger is content, not a menu).
25
+ */
26
+ onRowClick?: (index: number, event: ClickEvent) => void;
19
27
  }): React.ReactNode;
20
28
  //# sourceMappingURL=Ledger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Ledger.d.ts","sourceRoot":"","sources":["../../../../src/components/trajectory/Ledger.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAiBzB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AA6C1D,wBAAgB,MAAM,CAAC,EACrB,IAAI,EACJ,KAAK,EACL,MAAM,EACN,MAAM,EACN,KAAK,EACL,IAAI,EACJ,WAAW,EACX,WAAW,GACZ,EAAE;IACD,sCAAsC;IACtC,IAAI,EAAE,SAAS,QAAQ,EAAE,CAAA;IACzB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAA;IACb,yBAAyB;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAA;IACd,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAA;IACnB,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAA;CACpB,GAAG,KAAK,CAAC,SAAS,CAoJlB"}
1
+ {"version":3,"file":"Ledger.d.ts","sourceRoot":"","sources":["../../../../src/components/trajectory/Ledger.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAgBjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AA6C1D,wBAAgB,MAAM,CAAC,EACrB,IAAI,EACJ,KAAK,EACL,MAAM,EACN,MAAM,EACN,KAAK,EACL,IAAI,EACJ,WAAW,EACX,WAAW,EACX,UAAU,GACX,EAAE;IACD,sCAAsC;IACtC,IAAI,EAAE,SAAS,QAAQ,EAAE,CAAA;IACzB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAA;IACb,yBAAyB;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAA;IACd,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAA;IACnB,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAA;IACnB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CACxD,GAAG,KAAK,CAAC,SAAS,CAsKlB"}
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
2
3
  import { Box, Text, useTheme } from '../../ui.js';
3
4
  import { burstDurationMs, burstErrors, previewText } from '../../dsh-adapter/trajectory/index.js';
4
5
  import { costGlyph, formatDuration, formatClock, heatColor, KIND_BADGE, KIND_BADGE_BG, KIND_FG, KIND_GLYPH, ledgerLayout, } from '../../trajectory/format.js';
@@ -46,9 +47,10 @@ function spineGlyph(rows, index) {
46
47
  return SPINE.close;
47
48
  return SPINE.mid;
48
49
  }
49
- export function Ledger({ rows, start, height, cursor, width, tick, arrivalTick, arrivalFrom, }) {
50
+ export function Ledger({ rows, start, height, cursor, width, tick, arrivalTick, arrivalFrom, onRowClick, }) {
50
51
  const [themeName] = useTheme();
51
52
  const theme = getTheme(themeName);
53
+ const [hoverIndex, setHoverIndex] = React.useState(-1);
52
54
  const layout = ledgerLayout(width);
53
55
  const visible = rows.slice(start, start + height);
54
56
  const arriving = arrive(tick, arrivalTick);
@@ -65,6 +67,22 @@ export function Ledger({ rows, start, height, cursor, width, tick, arrivalTick,
65
67
  const running = node.status === 'running';
66
68
  const isNew = index >= arrivalFrom && arriving > 0;
67
69
  const duration = node.burst === undefined ? node.durationMs : burstDurationMs(node.burst);
70
+ // 鼠标:行点击跳光标;悬停在非焦点行亮出 dim ▸(轻指示,不刷背景)
71
+ const hovered = onRowClick !== undefined && hoverIndex === index;
72
+ const pointer = focused || hovered ? '▸' : ' ';
73
+ const rowEvents = onRowClick === undefined
74
+ ? undefined
75
+ : {
76
+ onClick: (event) => {
77
+ onRowClick(index, event);
78
+ },
79
+ onMouseEnter: () => {
80
+ setHoverIndex(index);
81
+ },
82
+ onMouseLeave: () => {
83
+ setHoverIndex(previous => (previous === index ? -1 : previous));
84
+ },
85
+ };
68
86
  // ── structural rows are RULES, not rows ────────────────────────────
69
87
  //
70
88
  // A ledger with five hundred entries needs chapters. Turn and step
@@ -82,7 +100,7 @@ export function Ledger({ rows, start, height, cursor, width, tick, arrivalTick,
82
100
  // attention than the work between them. Only the turn, which is the
83
101
  // session's actual chapter break, gets a rule.
84
102
  if (!isTurn) {
85
- return (_jsxs(Box, { flexDirection: "row", width: "100%", height: 1, flexShrink: 0, gap: 1, children: [_jsx(Box, { flexShrink: 0, children: _jsx(Text, { color: "subtle", children: `${focused ? '▸' : ' '}╵` }) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, overflow: "hidden", children: _jsx(Text, { color: focused ? 'suggestion' : 'subtle', wrap: "truncate", children: node.label }) }), _jsx(Box, { flexShrink: 0, children: _jsx(Text, { color: heatColor(duration), children: costGlyph(duration) }) }), _jsx(Box, { flexShrink: 0, justifyContent: "flex-end", width: 7, children: _jsx(Text, { color: heatColor(duration), children: right }) })] }, `${node.seq}:step`));
103
+ return (_jsxs(Box, { flexDirection: "row", width: "100%", height: 1, flexShrink: 0, gap: 1, ...rowEvents, children: [_jsx(Box, { flexShrink: 0, children: _jsx(Text, { color: "subtle", children: `${pointer}╵` }) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, overflow: "hidden", children: _jsx(Text, { color: focused ? 'suggestion' : 'subtle', wrap: "truncate", children: node.label }) }), _jsx(Box, { flexShrink: 0, children: _jsx(Text, { color: heatColor(duration), children: costGlyph(duration) }) }), _jsx(Box, { flexShrink: 0, justifyContent: "flex-end", width: 7, children: _jsx(Text, { color: heatColor(duration), children: right }) })] }, `${node.seq}:step`));
86
104
  }
87
105
  const tone = failed ? 'error' : running ? 'success' : 'inactiveShimmer';
88
106
  // Idle before a turn is wall-clock the session spent waiting on the
@@ -92,9 +110,9 @@ export function Ledger({ rows, start, height, cursor, width, tick, arrivalTick,
92
110
  const previous = rows[index - 1];
93
111
  const idle = previous === undefined ? 0 : node.time - (previous.time + (previous.durationMs ?? 0));
94
112
  const idleText = idle >= IDLE_FLOOR_MS ? ` ⋯ ${formatDuration(idle)}` : '';
95
- const head = `${focused ? '▸' : ' '}━━ ${node.label}${idleText} `;
113
+ const head = `${pointer}━━ ${node.label}${idleText} `;
96
114
  const fill = Math.max(2, width - stringWidth(head) - stringWidth(right) - 2);
97
- return (_jsx(Box, { width: "100%", height: 1, flexShrink: 0, children: _jsxs(Text, { color: tone, bold: true, children: [`${focused ? '▸' : ' '}━━ ${node.label}`, _jsx(Text, { color: "subtle", children: idleText }), _jsx(Text, { color: "inactive", children: ` ${'━'.repeat(fill)} ` }), _jsx(Text, { color: failed ? 'error' : heatColor(duration), children: right })] }) }, `${node.seq}:turn`));
115
+ return (_jsx(Box, { width: "100%", height: 1, flexShrink: 0, ...rowEvents, children: _jsxs(Text, { color: tone, bold: true, children: [`${pointer}━━ ${node.label}`, _jsx(Text, { color: "subtle", children: idleText }), _jsx(Text, { color: "inactive", children: ` ${'━'.repeat(fill)} ` }), _jsx(Text, { color: failed ? 'error' : heatColor(duration), children: right })] }) }, `${node.seq}:turn`));
98
116
  }
99
117
  const spineColor = failed ? 'error' : running ? 'success' : node.seed === true ? 'subtle' : 'inactive';
100
118
  const badgeBg = KIND_BADGE_BG[node.kind];
@@ -107,6 +125,6 @@ export function Ledger({ rows, start, height, cursor, width, tick, arrivalTick,
107
125
  const outcome = layout.outcome && node.outcome !== undefined && node.outcome !== ''
108
126
  ? previewText(node.outcome, Math.max(8, Math.floor(layout.detail * 0.3)))
109
127
  : '';
110
- return (_jsxs(Box, { flexDirection: "row", width: "100%", height: 1, flexShrink: 0, gap: 1, children: [_jsx(Box, { flexShrink: 0, children: _jsxs(Text, { color: spineColor, children: [focused ? '▸' : ' ', spineGlyph(rows, index)] }) }), layout.index && (_jsx(Box, { flexShrink: 0, width: 8, children: _jsx(Text, { color: "subtle", children: formatClock(node.time) }) })), _jsx(Box, { flexShrink: 0, children: _jsx(Text, { color: isNew ? mix(theme[KIND_FG[node.kind]], theme.text, arriving) : KIND_FG[node.kind], backgroundColor: badgeBg, bold: true, children: badge }) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, overflow: "hidden", children: _jsxs(Text, { wrap: "truncate", color: focused ? 'suggestion' : node.seed === true ? 'subtle' : undefined, children: [label, detail === '' ? '' : ' ', _jsx(Text, { color: focused ? 'suggestion' : 'inactive', children: detail }), outcome === '' ? '' : _jsx(Text, { color: "subtle", children: ` → ${outcome}` })] }) }), _jsx(Box, { flexShrink: 0, children: _jsx(Text, { color: running ? 'success' : heatColor(duration), children: costGlyph(duration) }) }), _jsx(Box, { flexShrink: 0, justifyContent: "flex-end", width: 7, children: _jsx(Text, { color: running ? 'success' : heatColor(duration), children: running ? '…' : duration === undefined ? '' : formatDuration(duration) }) })] }, `${node.seq}:${node.kind}`));
128
+ return (_jsxs(Box, { flexDirection: "row", width: "100%", height: 1, flexShrink: 0, gap: 1, ...rowEvents, children: [_jsx(Box, { flexShrink: 0, children: _jsxs(Text, { color: spineColor, children: [pointer, spineGlyph(rows, index)] }) }), layout.index && (_jsx(Box, { flexShrink: 0, width: 8, children: _jsx(Text, { color: "subtle", children: formatClock(node.time) }) })), _jsx(Box, { flexShrink: 0, children: _jsx(Text, { color: isNew ? mix(theme[KIND_FG[node.kind]], theme.text, arriving) : KIND_FG[node.kind], backgroundColor: badgeBg, bold: true, children: badge }) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, overflow: "hidden", children: _jsxs(Text, { wrap: "truncate", color: focused ? 'suggestion' : node.seed === true ? 'subtle' : undefined, children: [label, detail === '' ? '' : ' ', _jsx(Text, { color: focused ? 'suggestion' : 'inactive', children: detail }), outcome === '' ? '' : _jsx(Text, { color: "subtle", children: ` → ${outcome}` })] }) }), _jsx(Box, { flexShrink: 0, children: _jsx(Text, { color: running ? 'success' : heatColor(duration), children: costGlyph(duration) }) }), _jsx(Box, { flexShrink: 0, justifyContent: "flex-end", width: 7, children: _jsx(Text, { color: running ? 'success' : heatColor(duration), children: running ? '…' : duration === undefined ? '' : formatDuration(duration) }) })] }, `${node.seq}:${node.kind}`));
111
129
  }) }));
112
130
  }
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
+ import type { ClickEvent } from '../../ink/events/click-event.js';
2
3
  import type { WaveBand as Band } from '../../dsh-adapter/types.js';
3
- export declare function WaveBand({ band, width, cursorColumn, viewportStart, viewportEnd, matches, tick, alertTick, }: {
4
+ export declare function WaveBand({ band, width, cursorColumn, viewportStart, viewportEnd, matches, tick, alertTick, onColumnClick, }: {
4
5
  band: Band;
5
6
  /** Rendered width in cells; equals `band.buckets.length`. */
6
7
  width: number;
@@ -19,6 +20,14 @@ export declare function WaveBand({ band, width, cursorColumn, viewportStart, vie
19
20
  tick: number;
20
21
  /** Tick the most recent alert was triggered on. */
21
22
  alertTick: number;
23
+ /**
24
+ * Mouse pick (fullscreen): reports the clicked column (0-based within the
25
+ * band; the ruler row counts too — its ▐▌ bracket is the seek affordance).
26
+ * The scene jumps to that column's nearest event via bucket.firstIndex,
27
+ * which empty columns inherit from their predecessor for exactly this
28
+ * purpose. No hover: column density makes per-cell indication noise.
29
+ */
30
+ onColumnClick?: (column: number, event: ClickEvent) => void;
22
31
  }): React.ReactNode;
23
32
  /**
24
33
  * Convert a theme colour to the `#rrggbb` form chalk needs.
@@ -1 +1 @@
1
- {"version":3,"file":"WaveBand.d.ts","sourceRoot":"","sources":["../../../../src/components/trajectory/WaveBand.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,KAAK,EAAE,QAAQ,IAAI,IAAI,EAAe,MAAM,4BAA4B,CAAA;AAmD/E,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,KAAK,EACL,YAAY,EACZ,aAAa,EACb,WAAW,EACX,OAAO,EACP,IAAI,EACJ,SAAS,GACV,EAAE;IACD,IAAI,EAAE,IAAI,CAAA;IACV,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAA;IACb,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAA;IACpB,kEAAkE;IAClE,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAC7B,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAA;CAClB,GAAG,KAAK,CAAC,SAAS,CAgGlB;AAED;;;;;;GAMG;AACH,iBAAS,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMrC;AAED,6EAA6E;AAC7E,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE,CAAA"}
1
+ {"version":3,"file":"WaveBand.d.ts","sourceRoot":"","sources":["../../../../src/components/trajectory/WaveBand.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAIjE,OAAO,KAAK,EAAE,QAAQ,IAAI,IAAI,EAAe,MAAM,4BAA4B,CAAA;AAmD/E,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,KAAK,EACL,YAAY,EACZ,aAAa,EACb,WAAW,EACX,OAAO,EACP,IAAI,EACJ,SAAS,EACT,aAAa,GACd,EAAE;IACD,IAAI,EAAE,IAAI,CAAA;IACV,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAA;IACb,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAA;IACpB,kEAAkE;IAClE,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAC7B,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CAC5D,GAAG,KAAK,CAAC,SAAS,CA2GlB;AAED;;;;;;GAMG;AACH,iBAAS,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMrC;AAED,6EAA6E;AAC7E,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE,CAAA"}
@@ -50,7 +50,7 @@ function channelColor(channel, theme) {
50
50
  default: return theme.subtle;
51
51
  }
52
52
  }
53
- export function WaveBand({ band, width, cursorColumn, viewportStart, viewportEnd, matches, tick, alertTick, }) {
53
+ export function WaveBand({ band, width, cursorColumn, viewportStart, viewportEnd, matches, tick, alertTick, onColumnClick, }) {
54
54
  const [themeName] = useTheme();
55
55
  const theme = getTheme(themeName);
56
56
  if (band.buckets.length === 0) {
@@ -123,7 +123,12 @@ export function WaveBand({ band, width, cursorColumn, viewportStart, viewportEnd
123
123
  ? chalk.hex(toHex(theme.permission))(glyph)
124
124
  : chalk.hex(toHex(theme.subtle))(glyph);
125
125
  }
126
- return (_jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [_jsx(Text, { children: wave }), _jsx(Text, { children: rulerText })] }));
126
+ return (_jsxs(Box, { flexDirection: "column", flexShrink: 0, onClick: onColumnClick === undefined
127
+ ? undefined
128
+ : (event) => {
129
+ const column = Math.max(0, Math.min(band.buckets.length - 1, event.localCol));
130
+ onColumnClick(column, event);
131
+ }, children: [_jsx(Text, { children: wave }), _jsx(Text, { children: rulerText })] }));
127
132
  }
128
133
  /**
129
134
  * Convert a theme colour to the `#rrggbb` form chalk needs.
@@ -5,9 +5,10 @@ import { type SessionEvent } from '@deepseek-ai/dsh-session';
5
5
  import type { Context } from '@deepseek-ai/cordis';
6
6
  import { type CommandCompletion, type LocalCommand } from '../commands.js';
7
7
  import { type PreviewEntry, type SessionSummary } from './sessions/index.js';
8
+ import { type FileCandidate } from '../utils/fileSuggestions.js';
8
9
  import type { ProviderSetupHost } from './providerWizard.js';
9
10
  import { type SessionModeSpec } from '../sessionModes.js';
10
- import { type StatusBarConfig, type ToolBackground } from '../tuiDisplayPrefs.js';
11
+ import { type ScrollGutterMode, type StatusBarConfig, type ToolBackground } from '../tuiDisplayPrefs.js';
11
12
  import { type SubagentState } from './subagents.js';
12
13
  export type { SubagentState } from './subagents.js';
13
14
  import type { SpinnerMode } from '../components/Spinner/spinnerMode.js';
@@ -375,6 +376,10 @@ export interface Channel {
375
376
  readonly thinkingFold: 'preview' | 'full';
376
377
  /** Live tool-card background treatment. */
377
378
  readonly toolBackground: ToolBackground;
379
+ /** What the fullscreen transcript's right gutter shows (settings
380
+ * `dsh-tui.scrollGutter`: turn timeline / proportional scrollbar /
381
+ * nothing). */
382
+ readonly scrollGutter: ScrollGutterMode;
378
383
  /** Live status-footer visibility and compactness preferences. */
379
384
  readonly statusBar: Readonly<StatusBarConfig>;
380
385
  /** Whether the header's pixel whale art shows (settings `dsh-tui.whale`). */
@@ -389,10 +394,11 @@ export interface Channel {
389
394
  readonly contextBarEnabled: boolean;
390
395
  /**
391
396
  * Current same-session goal projection, when a goal exists. Derived live
392
- * from the durable `goal/change` context events (round-zero goal-sourced
393
- * user messages) in the session log — every goal mutation appends one, so
394
- * this snapshot tracks create/edit/pause/resume/complete/block/clear in
395
- * real time and replays correctly on resume/rewind.
397
+ * from the durable goal events in the session log — top-level
398
+ * `goal/change` snapshots (every goal mutation appends one) plus the
399
+ * goal-sourced continuation rounds that advance the counter — so this
400
+ * snapshot tracks create/edit/pause/resume/complete/block/clear in real
401
+ * time and replays correctly on resume/rewind.
396
402
  */
397
403
  readonly goal: ChannelGoal | undefined;
398
404
  /**
@@ -592,7 +598,12 @@ export interface Channel {
592
598
  settingsSections(): readonly TuiSettingsSection[];
593
599
  /** Subscribe to settings-section register/unregister events. */
594
600
  subscribeSettingsSections(listener: () => void): () => void;
595
- /** Top-level entries of the session cwd for `@` file completion. */
601
+ /** Structured `@` file completion, using the session's remote fs service. */
602
+ listFileCandidates(query: string, options?: {
603
+ signal?: AbortSignal;
604
+ topK?: number;
605
+ }): Promise<readonly FileCandidate[]>;
606
+ /** Backward-compatible top-level/recursive listing. */
596
607
  listFiles(): Promise<readonly string[]>;
597
608
  /** Every session the persistence backend stores, classified and unfiltered
598
609
  * — the browser (`/resume`) decides which of them a given view shows. */
@@ -734,6 +745,8 @@ export interface ChannelState {
734
745
  thinkingFold: 'preview' | 'full';
735
746
  /** Tool-card background treatment (see the public Channel type). */
736
747
  toolBackground: ToolBackground;
748
+ /** Transcript gutter mode (see the public Channel type). */
749
+ scrollGutter: ScrollGutterMode;
737
750
  /** Status-footer preferences (see the public Channel type). */
738
751
  statusBar: StatusBarConfig;
739
752
  /** Apply a diff-layout change (see the public Channel type). */
@@ -742,6 +755,8 @@ export interface ChannelState {
742
755
  setThinkingFold(mode: 'preview' | 'full'): void;
743
756
  /** Apply a tool-card background change. */
744
757
  setToolBackground(background: ToolBackground): void;
758
+ /** Apply a transcript gutter mode change. */
759
+ setScrollGutter(mode: ScrollGutterMode): void;
745
760
  /** Apply status-footer preference changes. */
746
761
  setStatusBar(config: Partial<StatusBarConfig>): void;
747
762
  /** Whale header art switch (see the public Channel type). */
@@ -867,6 +882,10 @@ export interface ChannelState {
867
882
  settingsSections(): readonly TuiSettingsSection[];
868
883
  /** Subscribe to settings-section register/unregister events. */
869
884
  subscribeSettingsSections(listener: () => void): () => void;
885
+ listFileCandidates(query: string, options?: {
886
+ signal?: AbortSignal;
887
+ topK?: number;
888
+ }): Promise<readonly FileCandidate[]>;
870
889
  listFiles(): Promise<readonly string[]>;
871
890
  listSessions(): Promise<readonly SessionSummary[]>;
872
891
  /** Trailing exchanges of a persisted session (see the public Channel type). */
@@ -932,6 +951,8 @@ export declare function createChannel(ctx: Context, initialAgent: Agent, options
932
951
  thinkingFold?: 'preview' | 'full';
933
952
  /** Tool-card background treatment; default `none`. */
934
953
  toolBackground?: ToolBackground;
954
+ /** Transcript gutter mode; default `timeline` (settings `dsh-tui.scrollGutter`). */
955
+ scrollGutter?: ScrollGutterMode;
935
956
  /** Status-footer field visibility and compactness. */
936
957
  statusBar?: Partial<StatusBarConfig>;
937
958
  /** Show the header's pixel whale art; default on. */