@deepseek-harness-tui/dsh-tui 0.10.2 → 0.11.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 (351) hide show
  1. package/README.md +175 -123
  2. package/bin/dsh-tui.js +748 -22
  3. package/cordis.patch.yml +42 -13
  4. package/cordis.yml +5 -2
  5. package/lib/types/activityPrefs.d.ts +24 -0
  6. package/lib/types/activityPrefs.d.ts.map +1 -1
  7. package/lib/types/activityPrefs.js +50 -1
  8. package/lib/types/adapter/channel/session-projection.d.ts.map +1 -1
  9. package/lib/types/adapter/channel/session-projection.js +2 -0
  10. package/lib/types/adapter/channel/state.d.ts.map +1 -1
  11. package/lib/types/adapter/channel/state.js +3 -1
  12. package/lib/types/adapter/channel/ui-policy.d.ts +4 -1
  13. package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
  14. package/lib/types/adapter/channel/ui-policy.js +6 -2
  15. package/lib/types/adapter/kernel/host-facade.d.ts.map +1 -1
  16. package/lib/types/adapter/kernel/host-facade.js +1 -0
  17. package/lib/types/adapter/kernel/replay.d.ts.map +1 -1
  18. package/lib/types/adapter/kernel/replay.js +3 -0
  19. package/lib/types/adapter/kernel/runtime.d.ts.map +1 -1
  20. package/lib/types/adapter/kernel/runtime.js +2 -0
  21. package/lib/types/adapter/kernel/slices/workspace.d.ts.map +1 -1
  22. package/lib/types/adapter/kernel/slices/workspace.js +1 -0
  23. package/lib/types/adapter/ports/channel-ui.d.ts +29 -5
  24. package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
  25. package/lib/types/adapter/ports/channel-view.d.ts +66 -12
  26. package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
  27. package/lib/types/adapter/ports/channel-workspace.d.ts +23 -0
  28. package/lib/types/adapter/ports/channel-workspace.d.ts.map +1 -1
  29. package/lib/types/adapter/ports/channel.d.ts +4 -1
  30. package/lib/types/adapter/ports/channel.d.ts.map +1 -1
  31. package/lib/types/adapter/ports/workspace.d.ts +2 -0
  32. package/lib/types/adapter/ports/workspace.d.ts.map +1 -1
  33. package/lib/types/adapter/upstream/workspace-driver.d.ts.map +1 -1
  34. package/lib/types/adapter/upstream/workspace-driver.js +10 -2
  35. package/lib/types/commands.d.ts.map +1 -1
  36. package/lib/types/commands.js +1 -0
  37. package/lib/types/components/ActivityLine.d.ts +7 -2
  38. package/lib/types/components/ActivityLine.d.ts.map +1 -1
  39. package/lib/types/components/ActivityLine.js +0 -8
  40. package/lib/types/components/ContextBarView.d.ts +15 -7
  41. package/lib/types/components/ContextBarView.d.ts.map +1 -1
  42. package/lib/types/components/ContextBarView.js +26 -22
  43. package/lib/types/components/ImagePreviewOverlay.d.ts.map +1 -1
  44. package/lib/types/components/ImagePreviewOverlay.js +11 -5
  45. package/lib/types/components/Markdown.d.ts +11 -1
  46. package/lib/types/components/Markdown.d.ts.map +1 -1
  47. package/lib/types/components/Markdown.js +20 -2
  48. package/lib/types/components/MermaidDiagram.d.ts +13 -0
  49. package/lib/types/components/MermaidDiagram.d.ts.map +1 -0
  50. package/lib/types/components/MermaidDiagram.js +61 -0
  51. package/lib/types/components/MessageList.d.ts +26 -1
  52. package/lib/types/components/MessageList.d.ts.map +1 -1
  53. package/lib/types/components/MessageList.js +74 -8
  54. package/lib/types/components/PageMargin.d.ts +1 -1
  55. package/lib/types/components/PromptInput.d.ts +37 -1
  56. package/lib/types/components/PromptInput.d.ts.map +1 -1
  57. package/lib/types/components/PromptInput.js +291 -30
  58. package/lib/types/components/ScrollbarGutter.d.ts +20 -5
  59. package/lib/types/components/ScrollbarGutter.d.ts.map +1 -1
  60. package/lib/types/components/ScrollbarGutter.js +88 -10
  61. package/lib/types/components/SplitDiffView.d.ts.map +1 -1
  62. package/lib/types/components/SplitDiffView.js +2 -1
  63. package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
  64. package/lib/types/components/StreamingMarkdown.js +30 -28
  65. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  66. package/lib/types/components/SubagentCard.js +12 -6
  67. package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
  68. package/lib/types/components/SubagentDetailScene.js +8 -3
  69. package/lib/types/components/Tooltip.d.ts.map +1 -1
  70. package/lib/types/components/Tooltip.js +45 -7
  71. package/lib/types/components/design-system/HintLine.d.ts +1 -2
  72. package/lib/types/components/design-system/HintLine.d.ts.map +1 -1
  73. package/lib/types/components/design-system/HintLine.js +1 -2
  74. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +2 -1
  75. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  76. package/lib/types/components/messages/AssistantThinkingMessage.js +2 -1
  77. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +2 -2
  78. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  79. package/lib/types/components/messages/AssistantToolUseMessage.js +30 -26
  80. package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
  81. package/lib/types/components/messages/UserPromptMessage.js +5 -7
  82. package/lib/types/components/messages/useImageInspection.d.ts.map +1 -1
  83. package/lib/types/components/messages/useImageInspection.js +19 -9
  84. package/lib/types/components/promptDraftCache.d.ts +102 -0
  85. package/lib/types/components/promptDraftCache.d.ts.map +1 -0
  86. package/lib/types/components/promptDraftCache.js +76 -0
  87. package/lib/types/components/questions/AskUserQuestionPanel.d.ts +17 -1
  88. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  89. package/lib/types/components/questions/AskUserQuestionPanel.js +40 -7
  90. package/lib/types/components/questions/QuestionMinimizedBar.d.ts +12 -0
  91. package/lib/types/components/questions/QuestionMinimizedBar.d.ts.map +1 -0
  92. package/lib/types/components/questions/QuestionMinimizedBar.js +43 -0
  93. package/lib/types/components/sessions/SessionListRow.d.ts +23 -1
  94. package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
  95. package/lib/types/components/sessions/SessionListRow.js +52 -5
  96. package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts +49 -0
  97. package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts.map +1 -0
  98. package/lib/types/components/workspaces/HomeWorkspaceRow.js +50 -0
  99. package/lib/types/dsh-adapter/activity-store.d.ts +221 -0
  100. package/lib/types/dsh-adapter/activity-store.d.ts.map +1 -0
  101. package/lib/types/dsh-adapter/activity-store.js +359 -0
  102. package/lib/types/dsh-adapter/bundled-presets.d.ts +10 -0
  103. package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -0
  104. package/lib/types/dsh-adapter/bundled-presets.js +80 -0
  105. package/lib/types/dsh-adapter/channel/action-readiness.d.ts +1 -1
  106. package/lib/types/dsh-adapter/channel/action-readiness.d.ts.map +1 -1
  107. package/lib/types/dsh-adapter/channel/action-readiness.js +3 -0
  108. package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts +1 -1
  109. package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts.map +1 -1
  110. package/lib/types/dsh-adapter/channel/agent-view-projection.js +19 -2
  111. package/lib/types/dsh-adapter/channel/background-action.d.ts +1 -1
  112. package/lib/types/dsh-adapter/channel/background-action.d.ts.map +1 -1
  113. package/lib/types/dsh-adapter/channel/background-action.js +53 -29
  114. package/lib/types/dsh-adapter/channel/binding-events.d.ts +8 -6
  115. package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
  116. package/lib/types/dsh-adapter/channel/binding-events.js +5 -4
  117. package/lib/types/dsh-adapter/channel/binding.d.ts +19 -2
  118. package/lib/types/dsh-adapter/channel/binding.d.ts.map +1 -1
  119. package/lib/types/dsh-adapter/channel/binding.js +78 -18
  120. package/lib/types/dsh-adapter/channel/compaction.d.ts +0 -1
  121. package/lib/types/dsh-adapter/channel/compaction.d.ts.map +1 -1
  122. package/lib/types/dsh-adapter/channel/compaction.js +0 -2
  123. package/lib/types/dsh-adapter/channel/composer-images.d.ts +5 -0
  124. package/lib/types/dsh-adapter/channel/composer-images.d.ts.map +1 -1
  125. package/lib/types/dsh-adapter/channel/composer-images.js +105 -6
  126. package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts +8 -0
  127. package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts.map +1 -1
  128. package/lib/types/dsh-adapter/channel/context-bookkeeping.js +3 -2
  129. package/lib/types/dsh-adapter/channel/ide-selection.d.ts +58 -0
  130. package/lib/types/dsh-adapter/channel/ide-selection.d.ts.map +1 -0
  131. package/lib/types/dsh-adapter/channel/ide-selection.js +226 -0
  132. package/lib/types/dsh-adapter/channel/input-delivery.d.ts +6 -1
  133. package/lib/types/dsh-adapter/channel/input-delivery.d.ts.map +1 -1
  134. package/lib/types/dsh-adapter/channel/input-delivery.js +9 -1
  135. package/lib/types/dsh-adapter/channel/local-actions.d.ts +3 -19
  136. package/lib/types/dsh-adapter/channel/local-actions.d.ts.map +1 -1
  137. package/lib/types/dsh-adapter/channel/local-actions.js +2 -1
  138. package/lib/types/dsh-adapter/channel/model-actions.d.ts +4 -1
  139. package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
  140. package/lib/types/dsh-adapter/channel/model-actions.js +82 -6
  141. package/lib/types/dsh-adapter/channel/model-switch.d.ts +1 -2
  142. package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
  143. package/lib/types/dsh-adapter/channel/model-switch.js +49 -31
  144. package/lib/types/dsh-adapter/channel/projection.d.ts +4 -0
  145. package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
  146. package/lib/types/dsh-adapter/channel/projection.js +29 -19
  147. package/lib/types/dsh-adapter/channel/reports.d.ts.map +1 -1
  148. package/lib/types/dsh-adapter/channel/reports.js +4 -12
  149. package/lib/types/dsh-adapter/channel/session-adoption.d.ts +1 -1
  150. package/lib/types/dsh-adapter/channel/session-adoption.d.ts.map +1 -1
  151. package/lib/types/dsh-adapter/channel/session-adoption.js +1 -0
  152. package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
  153. package/lib/types/dsh-adapter/channel/session-fork.js +26 -2
  154. package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts +4 -1
  155. package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts.map +1 -1
  156. package/lib/types/dsh-adapter/channel/session-live-adoption.js +2 -0
  157. package/lib/types/dsh-adapter/channel/session-metadata.d.ts +10 -0
  158. package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
  159. package/lib/types/dsh-adapter/channel/session-metadata.js +6 -4
  160. package/lib/types/dsh-adapter/channel/session-reset.d.ts +1 -1
  161. package/lib/types/dsh-adapter/channel/session-reset.d.ts.map +1 -1
  162. package/lib/types/dsh-adapter/channel/session-reset.js +0 -1
  163. package/lib/types/dsh-adapter/channel/session-resume.d.ts +12 -3
  164. package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
  165. package/lib/types/dsh-adapter/channel/session-resume.js +292 -94
  166. package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
  167. package/lib/types/dsh-adapter/channel/session-rewind.js +34 -16
  168. package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
  169. package/lib/types/dsh-adapter/channel/session-tree-actions.js +19 -3
  170. package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
  171. package/lib/types/dsh-adapter/channel/settings-host.js +4 -3
  172. package/lib/types/dsh-adapter/channel/state.d.ts +6 -1
  173. package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
  174. package/lib/types/dsh-adapter/channel/state.js +3 -3
  175. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts +21 -1
  176. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
  177. package/lib/types/dsh-adapter/channel/subagent-projection.js +173 -6
  178. package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
  179. package/lib/types/dsh-adapter/channel/transcript.js +6 -12
  180. package/lib/types/dsh-adapter/channel/types.d.ts +6 -1
  181. package/lib/types/dsh-adapter/channel/types.d.ts.map +1 -1
  182. package/lib/types/dsh-adapter/channel/workspace-actions.d.ts +4 -1
  183. package/lib/types/dsh-adapter/channel/workspace-actions.d.ts.map +1 -1
  184. package/lib/types/dsh-adapter/channel/workspace-actions.js +41 -1
  185. package/lib/types/dsh-adapter/channel.d.ts +1 -1
  186. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  187. package/lib/types/dsh-adapter/channel.js +82 -20
  188. package/lib/types/dsh-adapter/compat/index.d.ts +1 -1
  189. package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -1
  190. package/lib/types/dsh-adapter/compat/index.js +1 -1
  191. package/lib/types/dsh-adapter/compat/messages.d.ts +15 -0
  192. package/lib/types/dsh-adapter/compat/messages.d.ts.map +1 -0
  193. package/lib/types/dsh-adapter/compat/messages.js +15 -0
  194. package/lib/types/dsh-adapter/compat/sessionLog.d.ts +18 -0
  195. package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -1
  196. package/lib/types/dsh-adapter/compat/sessionLog.js +18 -3
  197. package/lib/types/dsh-adapter/compat/settings.d.ts +35 -0
  198. package/lib/types/dsh-adapter/compat/settings.d.ts.map +1 -0
  199. package/lib/types/dsh-adapter/compat/settings.js +57 -0
  200. package/lib/types/dsh-adapter/compat/shell.d.ts +25 -0
  201. package/lib/types/dsh-adapter/compat/shell.d.ts.map +1 -0
  202. package/lib/types/dsh-adapter/compat/shell.js +11 -0
  203. package/lib/types/dsh-adapter/contract.d.ts +5 -4
  204. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  205. package/lib/types/dsh-adapter/contract.js +17 -6
  206. package/lib/types/dsh-adapter/ide-channel.d.ts +224 -0
  207. package/lib/types/dsh-adapter/ide-channel.d.ts.map +1 -0
  208. package/lib/types/dsh-adapter/ide-channel.js +556 -0
  209. package/lib/types/dsh-adapter/index.d.ts +18 -3
  210. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  211. package/lib/types/dsh-adapter/index.js +32 -5
  212. package/lib/types/dsh-adapter/plugin.d.ts +4 -1
  213. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  214. package/lib/types/dsh-adapter/plugin.js +197 -49
  215. package/lib/types/dsh-adapter/preset-resolution.d.ts +8 -0
  216. package/lib/types/dsh-adapter/preset-resolution.d.ts.map +1 -1
  217. package/lib/types/dsh-adapter/preset-resolution.js +10 -0
  218. package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts +53 -0
  219. package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts.map +1 -0
  220. package/lib/types/dsh-adapter/session-mount-heartbeat.js +100 -0
  221. package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -1
  222. package/lib/types/dsh-adapter/sessionTree.js +3 -2
  223. package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
  224. package/lib/types/dsh-adapter/settings-sections.js +7 -4
  225. package/lib/types/dsh-adapter/subagents.d.ts +16 -3
  226. package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
  227. package/lib/types/dsh-adapter/subagents.js +92 -29
  228. package/lib/types/dsh-adapter/workspaces.d.ts +46 -3
  229. package/lib/types/dsh-adapter/workspaces.d.ts.map +1 -1
  230. package/lib/types/dsh-adapter/workspaces.js +116 -0
  231. package/lib/types/effortPrefs.d.ts +15 -3
  232. package/lib/types/effortPrefs.d.ts.map +1 -1
  233. package/lib/types/effortPrefs.js +37 -3
  234. package/lib/types/history.d.ts +13 -1
  235. package/lib/types/history.d.ts.map +1 -1
  236. package/lib/types/history.js +15 -2
  237. package/lib/types/homePrefs.d.ts +15 -0
  238. package/lib/types/homePrefs.d.ts.map +1 -0
  239. package/lib/types/homePrefs.js +53 -0
  240. package/lib/types/i18n.d.ts +347 -297
  241. package/lib/types/i18n.d.ts.map +1 -1
  242. package/lib/types/i18n.js +133 -85
  243. package/lib/types/ink/colorize.d.ts +10 -0
  244. package/lib/types/ink/colorize.d.ts.map +1 -1
  245. package/lib/types/ink/colorize.js +21 -0
  246. package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
  247. package/lib/types/ink/components/ScrollBox.js +12 -1
  248. package/lib/types/ink/dom.d.ts +1 -0
  249. package/lib/types/ink/dom.d.ts.map +1 -1
  250. package/lib/types/ink/hooks/use-copy-on-select.d.ts +5 -1
  251. package/lib/types/ink/hooks/use-copy-on-select.d.ts.map +1 -1
  252. package/lib/types/ink/hooks/use-copy-on-select.js +15 -1
  253. package/lib/types/ink/ink.d.ts.map +1 -1
  254. package/lib/types/ink/ink.js +36 -1
  255. package/lib/types/ink/log-update.d.ts.map +1 -1
  256. package/lib/types/ink/log-update.js +19 -1
  257. package/lib/types/ink/output.d.ts +10 -1
  258. package/lib/types/ink/output.d.ts.map +1 -1
  259. package/lib/types/ink/output.js +109 -17
  260. package/lib/types/ink/render-border.d.ts +6 -1
  261. package/lib/types/ink/render-border.d.ts.map +1 -1
  262. package/lib/types/ink/render-border.js +25 -9
  263. package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
  264. package/lib/types/ink/render-node-to-output.js +48 -6
  265. package/lib/types/ink/renderer.d.ts +6 -0
  266. package/lib/types/ink/renderer.d.ts.map +1 -1
  267. package/lib/types/ink/renderer.js +2 -1
  268. package/lib/types/ink/selection.d.ts +88 -0
  269. package/lib/types/ink/selection.d.ts.map +1 -1
  270. package/lib/types/ink/selection.js +164 -0
  271. package/lib/types/ink/sixel-graphics.d.ts +19 -1
  272. package/lib/types/ink/sixel-graphics.d.ts.map +1 -1
  273. package/lib/types/ink/sixel-graphics.js +124 -12
  274. package/lib/types/ink/terminal-image.d.ts +18 -1
  275. package/lib/types/ink/terminal-image.d.ts.map +1 -1
  276. package/lib/types/ink/terminal.d.ts +17 -0
  277. package/lib/types/ink/terminal.d.ts.map +1 -1
  278. package/lib/types/ink/terminal.js +20 -1
  279. package/lib/types/screens/Chat.d.ts +20 -1
  280. package/lib/types/screens/Chat.d.ts.map +1 -1
  281. package/lib/types/screens/Chat.js +296 -76
  282. package/lib/types/screens/SessionSupervisor.d.ts +84 -0
  283. package/lib/types/screens/SessionSupervisor.d.ts.map +1 -0
  284. package/lib/types/screens/SessionSupervisor.js +350 -0
  285. package/lib/types/screens/SessionTree.js +2 -2
  286. package/lib/types/screens/Settings.d.ts.map +1 -1
  287. package/lib/types/screens/Settings.js +32 -9
  288. package/lib/types/screens/StatusLine.d.ts +18 -1
  289. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  290. package/lib/types/screens/StatusLine.js +38 -19
  291. package/lib/types/screens/StatusMetrics.d.ts +79 -22
  292. package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
  293. package/lib/types/screens/StatusMetrics.js +153 -88
  294. package/lib/types/screens/sessionSupervisor/model.d.ts +83 -0
  295. package/lib/types/screens/sessionSupervisor/model.d.ts.map +1 -0
  296. package/lib/types/screens/sessionSupervisor/model.js +69 -0
  297. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts +120 -0
  298. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts.map +1 -0
  299. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.js +593 -0
  300. package/lib/types/sessionMounts.d.ts +272 -0
  301. package/lib/types/sessionMounts.d.ts.map +1 -0
  302. package/lib/types/sessionMounts.js +706 -0
  303. package/lib/types/sessions/format.d.ts.map +1 -1
  304. package/lib/types/sessions/format.js +4 -1
  305. package/lib/types/sessions/resumeFailure.d.ts +38 -0
  306. package/lib/types/sessions/resumeFailure.d.ts.map +1 -0
  307. package/lib/types/sessions/resumeFailure.js +58 -0
  308. package/lib/types/terminal-utils/mermaid.d.ts +44 -0
  309. package/lib/types/terminal-utils/mermaid.d.ts.map +1 -0
  310. package/lib/types/terminal-utils/mermaid.js +83 -0
  311. package/lib/types/tips.d.ts.map +1 -1
  312. package/lib/types/tips.js +175 -19
  313. package/lib/types/tuiDisplayPrefs.d.ts +7 -9
  314. package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
  315. package/lib/types/tuiDisplayPrefs.js +31 -28
  316. package/lib/types/update.d.ts +61 -0
  317. package/lib/types/update.d.ts.map +1 -1
  318. package/lib/types/update.js +194 -0
  319. package/lib/types/utils/fold-long-lines.d.ts +1 -1
  320. package/lib/types/utils/fold-long-lines.js +1 -1
  321. package/lib/types/utils/imageResize.d.ts +90 -0
  322. package/lib/types/utils/imageResize.d.ts.map +1 -0
  323. package/lib/types/utils/imageResize.js +272 -0
  324. package/lib/types/utils/keymap.d.ts +5 -1
  325. package/lib/types/utils/keymap.d.ts.map +1 -1
  326. package/lib/types/utils/keymap.js +23 -0
  327. package/lib/types/working-activity.d.ts +10 -9
  328. package/lib/types/working-activity.d.ts.map +1 -1
  329. package/lib/types/working-activity.js +17 -10
  330. package/lib/types/workspaces.d.ts +2 -1
  331. package/lib/types/workspaces.d.ts.map +1 -1
  332. package/lib/types/workspaces.js +1 -1
  333. package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +10 -10
  334. package/package.json +126 -105
  335. package/presets/liangshen/.dsh-tui-managed.json +1 -1
  336. package/presets/liangshen/agent.cordis.yml +15 -0
  337. package/lib/types/components/design-system/KeyboardShortcutHint.d.ts +0 -19
  338. package/lib/types/components/design-system/KeyboardShortcutHint.d.ts.map +0 -1
  339. package/lib/types/components/design-system/KeyboardShortcutHint.js +0 -14
  340. package/lib/types/dsh-adapter/channel/activity.d.ts +0 -20
  341. package/lib/types/dsh-adapter/channel/activity.d.ts.map +0 -1
  342. package/lib/types/dsh-adapter/channel/activity.js +0 -113
  343. package/lib/types/screens/AgentView.d.ts +0 -23
  344. package/lib/types/screens/AgentView.d.ts.map +0 -1
  345. package/lib/types/screens/AgentView.js +0 -546
  346. package/lib/types/screens/SessionBrowser.d.ts +0 -42
  347. package/lib/types/screens/SessionBrowser.d.ts.map +0 -1
  348. package/lib/types/screens/SessionBrowser.js +0 -911
  349. package/lib/types/terminal-utils/terminal.d.ts +0 -18
  350. package/lib/types/terminal-utils/terminal.d.ts.map +0 -1
  351. package/lib/types/terminal-utils/terminal.js +0 -96
@@ -0,0 +1,84 @@
1
+ import React from 'react';
2
+ import { SpinnerGlyph } from '../components/Spinner/SpinnerGlyph.js';
3
+ import type { ApprovalSnapshot } from '../dsh-adapter/approvals.js';
4
+ import type { TuiWorkspaceTarget } from '../workspaces.js';
5
+ import type { ChannelUi as Channel } from '../adapter/channel/ui-policy.js';
6
+ import { SupervisorLiveState, sessionMatchesQuery } from './sessionSupervisor/model.js';
7
+ export { sessionMatchesQuery };
8
+ /**
9
+ * The unified session screen — `/resume`, `/agentview`, `/home` and the 🏠
10
+ * button all land here.
11
+ *
12
+ * Those were three screens over one domain, which is why they kept needing
13
+ * patches to agree with each other. This is the single surface: the workspace
14
+ * rail on the left (the durable ledger a person manages — add, rename,
15
+ * remove), the sessions of the selected workspace on the right, and every
16
+ * session's LIVE state on its own row.
17
+ *
18
+ * The runtime it presents is a single model, and the screen is where that
19
+ * model becomes visible:
20
+ *
21
+ * - This terminal hosts many sessions at once. A row that is `working` keeps
22
+ * working when you leave it — switching changes what you are looking at, it
23
+ * does not stop anything. The parked rows stay in the list with a live
24
+ * glyph, so "where did my other session go" has an answer on screen.
25
+ * - A session held by another TUI terminal is shown as OCCUPIED (red, with the
26
+ * holder's pid) and cannot be entered. Two processes driving one
27
+ * append-only session log would interleave its events, so the screen refuses
28
+ * rather than races; the entry becomes available on its own once that
29
+ * process exits, because occupancy is proven by liveness rather than by a
30
+ * flag someone has to remember to clear.
31
+ *
32
+ * @param props - Channel, home directory, the opening/新 actions, and the live
33
+ * state + occupancy lookups the screen renders from.
34
+ * @returns The screen, or null while the host has no channel to read.
35
+ */
36
+ export declare function SessionSupervisor({ channel, home, onClose, onOpenSession, onNewSession, onStopSession, approval, onApprove, liveStateOf, }: {
37
+ channel: Channel;
38
+ /** Home directory, for collapsing paths to `~`. */
39
+ home: string;
40
+ /** Leave the screen and show the conversation. */
41
+ onClose(): void;
42
+ /** Mount a persisted session (the channel's unified resume path). */
43
+ onOpenSession(sessionId: string): Promise<boolean>;
44
+ /** Start a fresh session in the workspace at `path`. */
45
+ onNewSession(target: TuiWorkspaceTarget): Promise<boolean>;
46
+ /** Stop a background session of this terminal; false when it is not ours. */
47
+ onStopSession(sessionId: string): Promise<boolean>;
48
+ /**
49
+ * The parked approval ask (any session's), so a background session's
50
+ * permission prompt is answerable without leaving this screen — the one
51
+ * thing a parked session cannot wait indefinitely for.
52
+ */
53
+ approval: ApprovalSnapshot | null;
54
+ onApprove(outcome: 'allowed-once' | 'rejected'): void;
55
+ /**
56
+ * This terminal's live state for a session, or undefined when it has none.
57
+ * Read from the channel's agent-view projection so the list agrees with the
58
+ * overview's own rows by construction.
59
+ */
60
+ liveStateOf(sessionId: string): SupervisorLiveState | undefined;
61
+ }): React.ReactNode;
62
+ /**
63
+ * Scroll anchor for the rail: the first entry index to show.
64
+ *
65
+ * A pure helper (exported for the headless regression) because the rail's
66
+ * window has to hold the focused row without re-shuffling under a stationary
67
+ * cursor — the same anchoring rule the session list uses.
68
+ *
69
+ * `focus` is a plain entry index: the rail's rows ARE the ledger, so the cursor
70
+ * and the selection are one position and the window math takes that position
71
+ * directly. It used to be offset by the `+` row that led the rail, which is
72
+ * gone — a workspace joins the ledger by being a terminal's launch directory.
73
+ *
74
+ * `capacity` is a count of ENTRIES, not of terminal rows. It used to be handed
75
+ * the row count, which is wrong for this list in a way that hides the cursor:
76
+ * each entry is {@link WORKSPACE_ROW_LINES} rows tall, so treating rows as
77
+ * entries made the window believe it could show twice as many workspaces as it
78
+ * can, and the focused entry was simply clipped away by `overflow="hidden"`
79
+ * while the user navigated it blind.
80
+ */
81
+ export declare function railWindowTop(focus: number, entryCount: number, capacity: number): number;
82
+ /** Re-exported so a regression can drive the spinner without importing ink. */
83
+ export { SpinnerGlyph };
84
+ //# sourceMappingURL=SessionSupervisor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionSupervisor.d.ts","sourceRoot":"","sources":["../../../src/screens/SessionSupervisor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAA;AAarE,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAA;AAEpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AASnE,OAAO,KAAK,EAAqB,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAC7E,OAAO,KAAK,EAAE,SAAS,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAA;AAE3E,OAAO,EAAkN,mBAAmB,EAAsD,mBAAmB,EAAE,MAAM,8BAA8B,CAAA;AAC3V,OAAO,EAAE,mBAAmB,EAAE,CAAA;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,IAAI,EACJ,OAAO,EACP,aAAa,EACb,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,SAAS,EACT,WAAW,GACZ,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAA;IACZ,kDAAkD;IAClD,OAAO,IAAI,IAAI,CAAA;IACf,qEAAqE;IACrE,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAClD,wDAAwD;IACxD,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC1D,6EAA6E;IAC7E,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAClD;;;;OAIG;IACH,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACjC,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,UAAU,GAAG,IAAI,CAAA;IACrD;;;;OAIG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAAA;CAChE,GAAG,KAAK,CAAC,SAAS,CA8hBlB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOzF;AAED,+EAA+E;AAC/E,OAAO,EAAE,YAAY,EAAE,CAAA"}
@@ -0,0 +1,350 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { Box, Text, useInput, useTerminalSize } from '../ui.js';
4
+ import { t } from '../i18n.js';
5
+ import { Divider } from '../components/design-system/Divider.js';
6
+ import { HintLine } from '../components/design-system/HintLine.js';
7
+ import { SearchBox } from '../components/SearchBox.js';
8
+ import { PageInsetContext } from '../components/PageMargin.js';
9
+ import { HomeWorkspaceRow } from '../components/workspaces/HomeWorkspaceRow.js';
10
+ import { SessionListRow } from '../components/sessions/SessionListRow.js';
11
+ import { SpinnerGlyph } from '../components/Spinner/SpinnerGlyph.js';
12
+ import { ApprovalPanel } from '../components/approvals/ApprovalPanel.js';
13
+ import { useTerminalFocus } from '../ink/hooks/use-terminal-focus.js';
14
+ import { useAnimationFrame } from '../ink/hooks/use-animation-frame.js';
15
+ import { isPlainReturn, isMod } from '../utils/modifiers.js';
16
+ import { truncateWidth } from '../sessions/format.js';
17
+ import { useSessionSupervisor } from './sessionSupervisor/useSessionSupervisor.js';
18
+ import { SESSION_ROW_LINES, MENU_ACTIONS, MENU_WIDTH, MENU_HEIGHT, MENU_LABEL_KEYS, samePath, sessionMatchesQuery } from './sessionSupervisor/model.js';
19
+ export { sessionMatchesQuery };
20
+ /**
21
+ * The unified session screen — `/resume`, `/agentview`, `/home` and the 🏠
22
+ * button all land here.
23
+ *
24
+ * Those were three screens over one domain, which is why they kept needing
25
+ * patches to agree with each other. This is the single surface: the workspace
26
+ * rail on the left (the durable ledger a person manages — add, rename,
27
+ * remove), the sessions of the selected workspace on the right, and every
28
+ * session's LIVE state on its own row.
29
+ *
30
+ * The runtime it presents is a single model, and the screen is where that
31
+ * model becomes visible:
32
+ *
33
+ * - This terminal hosts many sessions at once. A row that is `working` keeps
34
+ * working when you leave it — switching changes what you are looking at, it
35
+ * does not stop anything. The parked rows stay in the list with a live
36
+ * glyph, so "where did my other session go" has an answer on screen.
37
+ * - A session held by another TUI terminal is shown as OCCUPIED (red, with the
38
+ * holder's pid) and cannot be entered. Two processes driving one
39
+ * append-only session log would interleave its events, so the screen refuses
40
+ * rather than races; the entry becomes available on its own once that
41
+ * process exits, because occupancy is proven by liveness rather than by a
42
+ * flag someone has to remember to clear.
43
+ *
44
+ * @param props - Channel, home directory, the opening/新 actions, and the live
45
+ * state + occupancy lookups the screen renders from.
46
+ * @returns The screen, or null while the host has no channel to read.
47
+ */
48
+ export function SessionSupervisor({ channel, home, onClose, onOpenSession, onNewSession, onStopSession, approval, onApprove, liveStateOf, }) {
49
+ const { columns, rows } = useTerminalSize();
50
+ const inset = React.useContext(PageInsetContext);
51
+ const isTerminalFocused = useTerminalFocus();
52
+ const { entries, sessions, loading, notice, setNotice, query, setQuery, holderOf, listedSessions, railEntries, countOf, railFocus, setRailFocus, setFocusSessionId, activePane, pins, menu, setMenu, rename, setRename, confirmRemove, setConfirmRemove, railRef, menuRef, queryRef, now, reload, selected, visibleSessions, sessionIndex, cardFocused, sessionAt, activateList, activateRail, railWidth, railVisible, sessionWidth, railEntryCapacity, sessionListHeight, persistPin, selectEntry, openSession, newSessionIn, renameEntry, removeEntry, stopSession, closeMenu, activateMenu, moveRail, moveSession, focusedSession, } = useSessionSupervisor({ channel, home, onOpenSession, onNewSession, onStopSession, liveStateOf, columns, rows });
53
+ useInput((input, key) => {
54
+ // Modal layers own the keyboard, in the same order they render.
55
+ if (rename !== undefined) {
56
+ if (key.escape) {
57
+ setRename(undefined);
58
+ return;
59
+ }
60
+ if (isPlainReturn(key)) {
61
+ const current = rename;
62
+ setRename(undefined);
63
+ renameEntry(current.path, current.draft);
64
+ return;
65
+ }
66
+ if (key.backspace || key.delete) {
67
+ setRename(current => (current === undefined ? current : { ...current, draft: current.draft.slice(0, -1) }));
68
+ return;
69
+ }
70
+ if (!isMod(key) && !key.meta && input && !key.return) {
71
+ const typed = input.replace(/[\r\n]+/gu, '');
72
+ if (typed !== '')
73
+ setRename(current => (current === undefined ? current : { ...current, draft: current.draft + typed }));
74
+ }
75
+ return;
76
+ }
77
+ if (confirmRemove !== undefined) {
78
+ if (isPlainReturn(key)) {
79
+ const path = confirmRemove;
80
+ setConfirmRemove(undefined);
81
+ removeEntry(path);
82
+ }
83
+ else if (key.escape) {
84
+ setConfirmRemove(undefined);
85
+ }
86
+ return;
87
+ }
88
+ if (menuRef.current !== undefined) {
89
+ if (key.upArrow) {
90
+ const current = menuRef.current;
91
+ const next = { ...current, item: (current.item + MENU_ACTIONS.length - 1) % MENU_ACTIONS.length };
92
+ menuRef.current = next;
93
+ setMenu(next);
94
+ }
95
+ else if (key.downArrow) {
96
+ const current = menuRef.current;
97
+ const next = { ...current, item: (current.item + 1) % MENU_ACTIONS.length };
98
+ menuRef.current = next;
99
+ setMenu(next);
100
+ }
101
+ else if (isPlainReturn(key)) {
102
+ const current = menuRef.current;
103
+ const entry = railEntries.find(candidate => samePath(candidate.path, current.path));
104
+ if (entry !== undefined)
105
+ activateMenu(entry, current.item);
106
+ }
107
+ else {
108
+ closeMenu();
109
+ }
110
+ return;
111
+ }
112
+ if (key.escape) {
113
+ if (notice !== undefined) {
114
+ setNotice(undefined);
115
+ return;
116
+ }
117
+ if (queryRef.current.length > 0) {
118
+ setQuery('');
119
+ return;
120
+ }
121
+ onClose();
122
+ return;
123
+ }
124
+ if (key.tab) {
125
+ // Shift+Tab keeps the keyboard route to the focused workspace's action
126
+ // menu. Plain Tab does nothing here: panes are chosen with ←/→ now, and
127
+ // Tab is the composer's business.
128
+ if (key.shift && activePane === 'rail') {
129
+ const entry = railEntries[railRef.current];
130
+ if (entry !== undefined) {
131
+ const next = { path: entry.path, ...keyboardMenuAnchor, item: 0 };
132
+ menuRef.current = next;
133
+ setMenu(next);
134
+ }
135
+ }
136
+ return;
137
+ }
138
+ // ←/→ choose the column. There is exactly one `❯` on screen because exactly
139
+ // one column owns the keyboard, and this is what moves that ownership.
140
+ if (key.leftArrow) {
141
+ activateRail();
142
+ return;
143
+ }
144
+ if (key.rightArrow) {
145
+ activateList();
146
+ return;
147
+ }
148
+ if (key.upArrow || key.wheelUp) {
149
+ if (activePane === 'rail')
150
+ moveRail(-1);
151
+ else
152
+ moveSession(-1);
153
+ return;
154
+ }
155
+ if (key.downArrow || key.wheelDown) {
156
+ if (activePane === 'rail')
157
+ moveRail(1);
158
+ else
159
+ moveSession(1);
160
+ return;
161
+ }
162
+ if (key.pageUp || key.pageDown) {
163
+ if (activePane === 'list')
164
+ moveSession(key.pageDown ? 1 : -1);
165
+ else
166
+ moveRail(key.pageDown ? 1 : -1);
167
+ return;
168
+ }
169
+ // The filter is a LIVE query, not a mode you enter: this screen has no
170
+ // second cursor for a text seat, and the rail/list already own the arrows
171
+ // (a seat would have to relearn them). So printable input goes straight to
172
+ // the query — without this branch the box rendered, focused, and could never
173
+ // be typed into.
174
+ if (key.backspace || key.delete) {
175
+ setQuery(text => text.slice(0, -1));
176
+ return;
177
+ }
178
+ if (isMod(key) && input === 'n') {
179
+ const entry = railEntries[railRef.current];
180
+ if (entry !== undefined)
181
+ newSessionIn(entry);
182
+ return;
183
+ }
184
+ if (isMod(key) && input === 'l') {
185
+ void reload();
186
+ return;
187
+ }
188
+ if (isMod(key) && input === 'x') {
189
+ if (focusedSession !== undefined)
190
+ stopSession(focusedSession);
191
+ return;
192
+ }
193
+ if (isPlainReturn(key)) {
194
+ // Enter means "the thing the active column is showing": its action menu
195
+ // for a workspace, that session for the session list. Ctrl/Cmd+Enter keeps
196
+ // the old "start a session in this workspace" shortcut from either column.
197
+ // Row 0 of the list is the new-session card, so it starts a session
198
+ // instead of opening one.
199
+ if (activePane === 'list') {
200
+ if (sessionIndex === 0) {
201
+ if (selected !== undefined)
202
+ newSessionIn(selected);
203
+ return;
204
+ }
205
+ // `sessionIndex` is derived from the SAME focus fact the render draws
206
+ // `❯` from, so Enter can only ever open the row the user is looking at.
207
+ const session = sessionAt(sessionIndex);
208
+ if (session !== undefined)
209
+ openSession(session);
210
+ return;
211
+ }
212
+ const entry = railEntries[railRef.current];
213
+ if (entry === undefined)
214
+ return;
215
+ if (key.ctrl || key.meta) {
216
+ newSessionIn(entry);
217
+ return;
218
+ }
219
+ const next = { path: entry.path, ...keyboardMenuAnchor, item: 0 };
220
+ menuRef.current = next;
221
+ setMenu(next);
222
+ return;
223
+ }
224
+ // Reached only when nothing above claimed the key: printable characters
225
+ // refine the filter. Control bytes are dropped so a terminal reporting an
226
+ // unknown key cannot type an invisible glyph into the query.
227
+ if (!isMod(key) && !key.meta && !key.super && input && !key.return) {
228
+ const typed = input.replace(/\p{Cc}/gu, '');
229
+ if (typed.length > 0)
230
+ setQuery(text => text + typed);
231
+ }
232
+ });
233
+ // Working rows animate their glyph. The shared clock only runs while at
234
+ // least one row is working, so an idle screen costs no extra ticks.
235
+ const workingCount = listedSessions.filter(session => liveStateOf(session.id)?.status === 'working').length;
236
+ const [, spinnerTime] = useAnimationFrame(workingCount > 0 ? 120 : null);
237
+ const spinnerFrame = Math.floor(spinnerTime / 120);
238
+ const railHint = rename !== undefined
239
+ ? t('home-hint-rename')
240
+ : confirmRemove !== undefined
241
+ ? t('home-hint-confirm-remove')
242
+ : menu !== undefined
243
+ ? t('home-hint-menu')
244
+ : activePane === 'rail'
245
+ ? t('home-hint-list')
246
+ : t('supervisor-hint-list');
247
+ const railWindowTopIndex = railWindowTop(railFocus, railEntries.length, railEntryCapacity);
248
+ const visibleRailRows = railEntries.slice(railWindowTopIndex, railWindowTopIndex + railEntryCapacity);
249
+ /** Content-local anchor for a keyboard-opened menu (screen coords minus inset). */
250
+ const keyboardMenuAnchor = { col: inset.x + 2, row: inset.y + 3 };
251
+ const filtered = query.trim().length > 0;
252
+ // Scroll window over the session rows, keeping the focused row visible
253
+ // without re-shuffling the list under a stationary cursor.
254
+ //
255
+ // The new-session card is a permanent row above this window, so the window is
256
+ // one card shorter and the cursor is expressed in the FULL list's space (card =
257
+ // 0): without that offset the window kept its old height and the cursor could
258
+ // land on a row that never made it on screen — a `❯` on an invisible row.
259
+ const capacity = Math.max(1, Math.floor(sessionListHeight / SESSION_ROW_LINES));
260
+ const sessionCapacity = Math.max(1, capacity - 1);
261
+ let sessionTop = Math.min(Math.max(0, sessionIndex - 1 - sessionCapacity + 1), Math.max(0, visibleSessions.length - sessionCapacity));
262
+ if (sessionIndex - 1 < sessionTop)
263
+ sessionTop = Math.max(0, sessionIndex - 1);
264
+ const visibleSessionRows = visibleSessions.slice(sessionTop, sessionTop + sessionCapacity);
265
+ const liveCount = listedSessions.filter(session => liveStateOf(session.id)?.live === true).length;
266
+ return (_jsxs(Box, { flexDirection: "column", width: columns, height: rows, onClick: menu !== undefined ? closeMenu : undefined, children: [_jsxs(Box, { height: 1, flexShrink: 0, overflow: "hidden", children: [_jsx(Text, { color: "remember", bold: true, children: ` ▣ ${t('supervisor-title')}` }), _jsx(Text, { dimColor: true, children: ` ${t('supervisor-subtitle')}` })] }), _jsx(Divider, { bleed: true }), _jsxs(Box, { flexDirection: "row", flexGrow: 1, flexShrink: 1, overflow: "hidden", children: [railVisible && (_jsxs("ink-box", { style: { flexDirection: 'column', width: railWidth, height: '100%', flexShrink: 0, overflow: 'hidden' }, onClick: activateRail, onMouseEnter: activateRail, onWheel: (event) => {
267
+ moveRail(event.deltaY >= 0 ? 1 : -1);
268
+ }, children: [_jsx(Box, { height: 1, flexShrink: 0, overflow: "hidden", paddingX: 1, children: _jsx(Text, { dimColor: true, children: truncateWidth(t('home-section-workspaces', { n: railEntries.length }), railWidth - 2) }) }), !loading && railEntries.length === 0 && (_jsx(Box, { paddingX: 1, children: _jsx(Text, { dimColor: true, italic: true, wrap: "truncate-end", children: truncateWidth(t('home-no-workspaces'), railWidth - 2) }) })), visibleRailRows.map((entry) => {
269
+ const absolute = railEntries.indexOf(entry);
270
+ return (_jsx(HomeWorkspaceRow, { title: entry.title, path: entry.path, home: home, sessionCount: countOf(entry), present: entry.present, selected: selected !== undefined && selected.id === entry.id, focused: activePane === 'rail' && railFocus === absolute, width: railWidth, onSelect: (event) => {
271
+ event.stopImmediatePropagation();
272
+ railRef.current = absolute;
273
+ setRailFocus(absolute);
274
+ selectEntry(entry);
275
+ }, onMenu: (event) => {
276
+ event.stopImmediatePropagation();
277
+ railRef.current = absolute;
278
+ setRailFocus(absolute);
279
+ const next = { path: entry.path, col: event.col, row: event.row, item: 0 };
280
+ menuRef.current = next;
281
+ setMenu(next);
282
+ } }, entry.id));
283
+ }), _jsx(Box, { flexGrow: 1 }), _jsx(Box, { flexShrink: 0, paddingX: 1, children: _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: railHint }) }) })] })), railVisible && (_jsx(Box, { width: 1, flexShrink: 0, flexDirection: "column", children: _jsx(Text, { dimColor: true, children: '│' }) })), _jsxs(Box, { flexDirection: "column", width: sessionWidth, height: "100%", flexShrink: 0, overflow: "hidden", onClick: activateList, onMouseEnter: activateList, children: [_jsx(Box, { height: 1, flexShrink: 0, overflow: "hidden", children: _jsxs(Box, { flexShrink: 1, overflow: "hidden", children: [_jsx(Text, { color: "remember", bold: true, children: truncateWidth(` ${t('home-sessions-title', { name: selected?.title ?? t('supervisor-title') })}`, Math.max(4, sessionWidth - 3)) }), _jsx(Text, { dimColor: true, children: ` ${truncateWidth(t('supervisor-counts', { working: workingCount, live: liveCount, total: visibleSessions.length }), Math.max(4, sessionWidth - 3))}` })] }) }), _jsx(Box, { height: 1, flexShrink: 0, paddingX: 1, children: _jsx(SearchBox, { query: query, isFocused: activePane === 'list', isTerminalFocused: isTerminalFocused, placeholder: truncateWidth(t('supervisor-filter-placeholder'), Math.max(8, sessionWidth - 6)), prefix: "/", borderless: true, width: Math.max(8, sessionWidth - 2) }) }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, onClick: (event) => {
284
+ event.stopImmediatePropagation();
285
+ if (selected !== undefined)
286
+ newSessionIn(selected);
287
+ }, children: [_jsxs(Box, { height: 1, flexShrink: 0, overflow: "hidden", children: [_jsx(Text, { color: cardFocused ? 'success' : 'subtle', children: cardFocused ? '❯ ' : ' ' }), _jsx(Text, { color: cardFocused ? 'success' : undefined, bold: cardFocused, children: t('supervisor-new-session') })] }), _jsx(Box, { height: 1, flexShrink: 0, overflow: "hidden", children: _jsx(Text, { dimColor: true, children: ` ${truncateWidth(t('supervisor-new-session-hint', { name: selected?.title ?? t('supervisor-title') }), Math.max(8, sessionWidth - 3))}` }) })] }), _jsxs("ink-box", { style: { flexDirection: 'column', flexGrow: 1, flexShrink: 1, overflow: 'hidden' }, onWheel: (event) => {
288
+ moveSession(event.deltaY >= 0 ? 1 : -1);
289
+ }, children: [loading && _jsx(Text, { dimColor: true, italic: true, children: ` ${truncateWidth(t('home-sessions-loading'), sessionWidth - 2)}` }), !loading && visibleSessions.length === 0 && (_jsx(Text, { dimColor: true, italic: true, children: ` ${truncateWidth(filtered ? t('supervisor-no-matches') : t('home-no-sessions'), sessionWidth - 2)}` })), visibleSessionRows.map((session, index) => {
290
+ const state = liveStateOf(session.id);
291
+ const holder = holderOf(session.id);
292
+ return (_jsx(SessionListRow, { session: session, width: sessionWidth, depth: 0, focused: activePane === 'list' && sessionTop + index + 1 === sessionIndex, pinned: pins.has(session.id), now: now, liveStatus: state?.live === true ? state.status : undefined, current: state?.current === true, occupiedPid: holder, spinner: { frame: spinnerFrame, time: spinnerTime }, onClick: (event) => {
293
+ event.stopImmediatePropagation();
294
+ setFocusSessionId(session.id);
295
+ openSession(session);
296
+ }, onTogglePin: () => {
297
+ setFocusSessionId(session.id);
298
+ persistPin(session.id, !pins.has(session.id));
299
+ }, onContextMenu: (event) => {
300
+ setFocusSessionId(session.id);
301
+ const entry = selected;
302
+ if (entry === undefined)
303
+ return;
304
+ const next = { path: entry.path, col: event.col, row: event.row, item: 0 };
305
+ menuRef.current = next;
306
+ setMenu(next);
307
+ } }, session.id));
308
+ })] }), _jsx(Box, { flexShrink: 0, height: 1, overflow: "hidden", children: _jsx(Text, { color: notice?.tone === 'error' ? 'error' : 'success', children: notice === undefined ? ' ' : ` ${truncateWidth(notice.text, Math.max(0, sessionWidth - 3))}` }) }), _jsx(Box, { flexShrink: 0, children: _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: filtered ? t('supervisor-hint-filter') : t('supervisor-hint-list') }) }) })] })] }), rename !== undefined && (_jsx(Box, { height: 1, flexShrink: 0, children: _jsx(SearchBox, { query: rename.draft, isFocused: true, isTerminalFocused: isTerminalFocused, placeholder: t('home-rename-placeholder'), prefix: "\u270E", borderless: true, width: "100%" }) })), confirmRemove !== undefined && (_jsx(Box, { flexShrink: 0, paddingX: 1, onClick: () => {
309
+ const path = confirmRemove;
310
+ setConfirmRemove(undefined);
311
+ removeEntry(path);
312
+ }, children: _jsx(Text, { color: "error", children: truncateWidth(` ${t('home-remove-title', { name: railEntries.find(entry => samePath(entry.path, confirmRemove))?.title ?? confirmRemove })} · ${t('home-remove-detail')}`, columns - 3) }) })), menu !== undefined && (_jsx(Box, { position: "absolute", left: Math.max(0, Math.min(menu.col - inset.x + 1, Math.max(0, columns - MENU_WIDTH))), top: Math.max(0, Math.min(menu.row - inset.y + 1, Math.max(0, rows - MENU_HEIGHT))), width: MENU_WIDTH, height: MENU_HEIGHT, flexDirection: "column", flexShrink: 0, borderStyle: "round", borderColor: "permission", backgroundColor: "toolCardBackground", children: MENU_ACTIONS.map((action, index) => (_jsx(Box, { height: 1, flexShrink: 0, backgroundColor: index === menu.item ? 'userMessageBackgroundHover' : undefined, onMouseEnter: () => setMenu(current => (current === undefined ? current : { ...current, item: index })), onClick: (event) => {
313
+ event.stopImmediatePropagation();
314
+ const entry = railEntries.find(candidate => samePath(candidate.path, menu.path));
315
+ if (entry !== undefined)
316
+ activateMenu(entry, index);
317
+ }, children: _jsx(Text, { color: action === 'remove' ? 'error' : undefined, children: ` ${index === menu.item ? '❯' : ' '} ${t(MENU_LABEL_KEYS[action])}` }) }, action))) })), approval !== null && (_jsx(Box, { flexShrink: 0, flexDirection: "column", position: "absolute", bottom: 1, left: 0, width: columns, children: _jsx(ApprovalPanel, { approval: approval, background: approval.agentId !== channel.agentId, onDecide: onApprove }) }))] }));
318
+ }
319
+ /**
320
+ * Scroll anchor for the rail: the first entry index to show.
321
+ *
322
+ * A pure helper (exported for the headless regression) because the rail's
323
+ * window has to hold the focused row without re-shuffling under a stationary
324
+ * cursor — the same anchoring rule the session list uses.
325
+ *
326
+ * `focus` is a plain entry index: the rail's rows ARE the ledger, so the cursor
327
+ * and the selection are one position and the window math takes that position
328
+ * directly. It used to be offset by the `+` row that led the rail, which is
329
+ * gone — a workspace joins the ledger by being a terminal's launch directory.
330
+ *
331
+ * `capacity` is a count of ENTRIES, not of terminal rows. It used to be handed
332
+ * the row count, which is wrong for this list in a way that hides the cursor:
333
+ * each entry is {@link WORKSPACE_ROW_LINES} rows tall, so treating rows as
334
+ * entries made the window believe it could show twice as many workspaces as it
335
+ * can, and the focused entry was simply clipped away by `overflow="hidden"`
336
+ * while the user navigated it blind.
337
+ */
338
+ export function railWindowTop(focus, entryCount, capacity) {
339
+ const entries = Math.max(1, capacity);
340
+ if (focus < 0)
341
+ return 0;
342
+ let top = Math.max(0, focus - entries + 1);
343
+ if (focus < top)
344
+ top = focus;
345
+ if (focus >= top + entries)
346
+ top = focus - entries + 1;
347
+ return Math.min(top, Math.max(0, entryCount - entries));
348
+ }
349
+ /** Re-exported so a regression can drive the spinner without importing ink. */
350
+ export { SpinnerGlyph };
@@ -335,8 +335,8 @@ export function SessionTree({ channel, currentSessionId, onClose, onRestoreText,
335
335
  askAdopt(entry);
336
336
  };
337
337
  // ── Keyboard ────────────────────────────────────────────────────────────
338
- // Keys are read through refs for the same reason SessionBrowser does it:
339
- // several key events can arrive in one stdin chunk before React re-renders.
338
+ // Keys are read through refs for the same reason the other keyed screens do
339
+ // it: several key events can arrive in one stdin chunk before React re-renders.
340
340
  const focusIndexRef = React.useRef(focusIndex);
341
341
  focusIndexRef.current = focusIndex;
342
342
  const visibleRef = React.useRef(visible);
@@ -1 +1 @@
1
- {"version":3,"file":"Settings.d.ts","sourceRoot":"","sources":["../../../src/screens/Settings.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAczB,OAAO,KAAK,EAAE,SAAS,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAA;AAuP3E;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EACP,OAAO,GACR,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,GAAG,KAAK,CAAC,SAAS,CAgiBlB"}
1
+ {"version":3,"file":"Settings.d.ts","sourceRoot":"","sources":["../../../src/screens/Settings.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAczB,OAAO,KAAK,EAAE,SAAS,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAA;AAuP3E;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EACP,OAAO,GACR,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,GAAG,KAAK,CAAC,SAAS,CAojBlB"}
@@ -96,8 +96,8 @@ function CardRow({ children, highlight, color = CARD_BORDER, }) {
96
96
  * their `*` / badge feedback.
97
97
  */
98
98
  export function Settings({ channel, onClose, }) {
99
- // Explicit terminal size (not flexGrow) — the same rule SessionBrowser's
100
- // root follows inside the alternate screen's fixed-height box.
99
+ // Explicit terminal size (not flexGrow) — the same rule the full-screen
100
+ // session views follow inside the alternate screen's fixed-height box.
101
101
  const { columns, rows } = useTerminalSize();
102
102
  // channel caches the host — a fresh object per call would re-fire the
103
103
  // host-keyed effects below on every render (an endless render loop).
@@ -308,7 +308,7 @@ export function Settings({ channel, onClose, }) {
308
308
  setEditing(state => state === null ? null : { ...state, draft: state.draft.slice(0, -1) });
309
309
  }
310
310
  else if (!isMod(key) && !key.meta && !key.super && input && !key.return) {
311
- // Only real characters reach the draft (see SessionBrowser's query).
311
+ // Only real characters reach the draft (see the supervisor's filter).
312
312
  const typed = input.replace(/\p{Cc}/gu, '');
313
313
  if (typed.length > 0) {
314
314
  setEditing(state => state === null ? null : { ...state, draft: state.draft + typed });
@@ -504,10 +504,22 @@ export function Settings({ channel, onClose, }) {
504
504
  }
505
505
  }
506
506
  // Focus-follow window: keep the focused entry fully inside the viewport.
507
+ // The card chrome rows (top border + title, bottom border, section gaps)
508
+ // carry no focus, so the follow rules alone can push them out of the window
509
+ // at the ends of the scroll range — the clamp below keeps the window inside
510
+ // the list's physical bounds, and pins it there while the focus sits at
511
+ // either end of the focus order.
507
512
  let totalLines = 0;
508
513
  let focusedOffset = 0;
509
514
  let focusedLines = 1;
515
+ let firstFocusOffset;
516
+ let lastFocusOffset;
510
517
  for (const entry of entries) {
518
+ if (entry.focus !== undefined) {
519
+ if (firstFocusOffset === undefined)
520
+ firstFocusOffset = totalLines;
521
+ lastFocusOffset = totalLines;
522
+ }
511
523
  if (entry.focus === effFocus) {
512
524
  focusedOffset = totalLines;
513
525
  focusedLines = entry.lines;
@@ -518,15 +530,26 @@ export function Settings({ channel, onClose, }) {
518
530
  // permanent (blank while quiet) so a save/discard toast never shifts the
519
531
  // list above it.
520
532
  const viewport = Math.max(1, rows - 4);
533
+ const maxStart = Math.max(0, totalLines - viewport);
521
534
  React.useEffect(() => {
522
535
  setWindowStart(start => {
523
- if (focusedOffset < start)
524
- return focusedOffset;
525
- if (focusedOffset + focusedLines > start + viewport)
526
- return focusedOffset + focusedLines - viewport;
527
- return start;
536
+ let next = Math.min(Math.max(0, start), maxStart);
537
+ if (focusedOffset < next)
538
+ next = focusedOffset;
539
+ if (focusedOffset + focusedLines > next + viewport)
540
+ next = focusedOffset + focusedLines - viewport;
541
+ // Focus at either end of the focus order pins the window to the list's
542
+ // edge (the card title / bottom border stay visible once the scroll
543
+ // bottoms out) — but only while the focused row stays inside the pinned
544
+ // window: a viewport too small for the edge must keep hiding chrome
545
+ // rather than ever hiding the focus.
546
+ if (firstFocusOffset !== undefined && focusedOffset <= firstFocusOffset && focusedOffset + focusedLines <= viewport)
547
+ return 0;
548
+ if (lastFocusOffset !== undefined && focusedOffset >= lastFocusOffset && focusedOffset >= maxStart)
549
+ return maxStart;
550
+ return next;
528
551
  });
529
- }, [focusedOffset, focusedLines, viewport]);
552
+ }, [focusedOffset, focusedLines, viewport, maxStart, firstFocusOffset, lastFocusOffset]);
530
553
  let entryOffset = 0;
531
554
  const visible = entries.filter(entry => {
532
555
  const start = entryOffset;
@@ -1,10 +1,14 @@
1
1
  import React from 'react';
2
+ import { type ActivityLineValue } from '../components/ActivityLine.js';
2
3
  import type { ChannelUi as Channel } from '../adapter/channel/ui-policy.js';
3
4
  import type { WaveBand } from '../dsh-adapter/types.js';
4
- export declare function StatusLine({ channel, selectionActive, helpOpen, wake, }: {
5
+ export declare function StatusLine({ channel, selectionActive, helpOpen, wake, activity: projectedActivity, }: {
5
6
  channel: Channel;
6
7
  selectionActive?: boolean;
7
8
  helpOpen?: boolean;
9
+ /** Activity value published by the working-activity plugin for this session.
10
+ * Preferred over the channel's own copy when the composition provides it. */
11
+ activity?: ActivityLineValue;
8
12
  /**
9
13
  * The session projected onto the status line's few columns, plus the
10
14
  * animation tick and the self-retiring key hint.
@@ -27,5 +31,18 @@ type UsageSnapshot = {
27
31
  };
28
32
  /** Return the prompt-cache hit rate, or nothing when usage is unavailable. */
29
33
  export declare function formatCacheHitRate(usage: UsageSnapshot | undefined): string | undefined;
34
+ /**
35
+ * The prompt footer's live IDE-selection badge (T-FIX-02), mirroring Claude
36
+ * Code's `⧉ N lines selected`: English only (like every other footer field),
37
+ * singular/plural aware, line count from the snapshot's 0-based inclusive
38
+ * range. `undefined` (no IDE yet / cleared by an isEmpty notification)
39
+ * renders no field at all — a manually launched session never shows a
40
+ * placeholder. Exported for scripts/verify-ide-channel.tsx.
41
+ */
42
+ export declare function formatSelectionBadge(selection: {
43
+ startLine: number;
44
+ endLine: number;
45
+ isEmpty?: boolean;
46
+ } | undefined): string | undefined;
30
47
  export {};
31
48
  //# sourceMappingURL=StatusLine.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"StatusLine.d.ts","sourceRoot":"","sources":["../../../src/screens/StatusLine.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAczB,OAAO,KAAK,EAAE,SAAS,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAA;AAe3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAoHvD,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,eAAuB,EACvB,QAAgB,EAChB,IAAI,GACL,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CACvD,qBAoZA;AAED,KAAK,aAAa,GAAG;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAuKD,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAKvF"}
1
+ {"version":3,"file":"StatusLine.d.ts","sourceRoot":"","sources":["../../../src/screens/StatusLine.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,OAAO,EAAoC,KAAK,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AAOxG,OAAO,KAAK,EAAE,SAAS,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAA;AAkB3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAqHvD,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,eAAuB,EACvB,QAAgB,EAChB,IAAI,EACJ,QAAQ,EAAE,iBAAiB,GAC5B,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;kFAC8E;IAC9E,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CACvD,qBA8ZA;AAED,KAAK,aAAa,GAAG;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AA4KD,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAKvF;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EACL;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GACzD,SAAS,GACZ,MAAM,GAAG,SAAS,CAIpB"}