@deepseek-harness-tui/dsh-tui 0.9.0 → 0.9.2

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 (307) hide show
  1. package/README.md +69 -256
  2. package/bin/dsh-tui.js +172 -5
  3. package/cordis.patch.yml +16 -4
  4. package/dsh-ecosystem-spec/protocols/profile-definitions.d.ts +13 -13
  5. package/dsh-ecosystem-spec/protocols/profile-definitions.js +59 -59
  6. package/dsh-ecosystem-spec/protocols/tui-channel-http.d.ts +15 -15
  7. package/dsh-ecosystem-spec/protocols/tui-channel-http.js +32 -32
  8. package/dsh-ecosystem-spec/protocols/tui-channel.d.ts +59 -59
  9. package/dsh-ecosystem-spec/protocols/tui-channel.js +166 -166
  10. package/dsh-ecosystem-spec/protocols/tui-contributions.d.ts +42 -42
  11. package/dsh-ecosystem-spec/protocols/tui-contributions.js +143 -143
  12. package/dsh-ecosystem-spec/registry/README.md +14 -14
  13. package/dsh-ecosystem-spec/registry/host-descriptor.tui.example.json +56 -56
  14. package/dsh-ecosystem-spec/registry/permissions-0.1.json +13 -13
  15. package/dsh-ecosystem-spec/registry/registry-0.15.json +149 -149
  16. package/lib/types/cc/hyperlink.d.ts +7 -1
  17. package/lib/types/cc/hyperlink.d.ts.map +1 -1
  18. package/lib/types/cc/hyperlink.js +3 -2
  19. package/lib/types/cc/markdown.d.ts.map +1 -1
  20. package/lib/types/cc/markdown.js +33 -3
  21. package/lib/types/cc/sessionColors.d.ts +27 -0
  22. package/lib/types/cc/sessionColors.d.ts.map +1 -0
  23. package/lib/types/cc/sessionColors.js +39 -0
  24. package/lib/types/commands.d.ts.map +1 -1
  25. package/lib/types/commands.js +6 -0
  26. package/lib/types/components/AutoRecapRow.d.ts +23 -0
  27. package/lib/types/components/AutoRecapRow.d.ts.map +1 -0
  28. package/lib/types/components/AutoRecapRow.js +23 -0
  29. package/lib/types/components/ColorPicker.d.ts +17 -0
  30. package/lib/types/components/ColorPicker.d.ts.map +1 -0
  31. package/lib/types/components/ColorPicker.js +20 -0
  32. package/lib/types/components/CommandSuggestions.d.ts +3 -1
  33. package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
  34. package/lib/types/components/ContextBarView.d.ts +33 -0
  35. package/lib/types/components/ContextBarView.d.ts.map +1 -0
  36. package/lib/types/components/ContextBarView.js +46 -0
  37. package/lib/types/components/EffortInputBorder.d.ts +12 -1
  38. package/lib/types/components/EffortInputBorder.d.ts.map +1 -1
  39. package/lib/types/components/EffortInputBorder.js +22 -5
  40. package/lib/types/components/FileActionsPanel.d.ts +22 -0
  41. package/lib/types/components/FileActionsPanel.d.ts.map +1 -0
  42. package/lib/types/components/FileActionsPanel.js +28 -0
  43. package/lib/types/components/FileSuggestions.d.ts +3 -1
  44. package/lib/types/components/FileSuggestions.d.ts.map +1 -1
  45. package/lib/types/components/MessageList.d.ts +3 -1
  46. package/lib/types/components/MessageList.d.ts.map +1 -1
  47. package/lib/types/components/MessageList.js +13 -6
  48. package/lib/types/components/ModelPicker.d.ts +26 -4
  49. package/lib/types/components/ModelPicker.d.ts.map +1 -1
  50. package/lib/types/components/ModelPicker.js +26 -6
  51. package/lib/types/components/PromptInput.d.ts.map +1 -1
  52. package/lib/types/components/PromptInput.js +365 -57
  53. package/lib/types/components/RecapPanel.d.ts +25 -0
  54. package/lib/types/components/RecapPanel.d.ts.map +1 -0
  55. package/lib/types/components/RecapPanel.js +55 -0
  56. package/lib/types/components/ScrollbarGutter.d.ts.map +1 -1
  57. package/lib/types/components/ScrollbarGutter.js +55 -4
  58. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  59. package/lib/types/components/SubagentCard.js +6 -4
  60. package/lib/types/components/SuggestionCard.d.ts +4 -2
  61. package/lib/types/components/SuggestionCard.d.ts.map +1 -1
  62. package/lib/types/components/TimelineRail.d.ts.map +1 -1
  63. package/lib/types/components/TimelineRail.js +9 -2
  64. package/lib/types/components/design-system/ThemeProvider.d.ts +7 -0
  65. package/lib/types/components/design-system/ThemeProvider.d.ts.map +1 -1
  66. package/lib/types/components/design-system/ThemeProvider.js +2 -1
  67. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +8 -1
  68. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  69. package/lib/types/components/messages/AssistantToolUseMessage.js +36 -8
  70. package/lib/types/components/questions/AskUserQuestionPanel.d.ts +7 -3
  71. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  72. package/lib/types/components/questions/AskUserQuestionPanel.js +41 -9
  73. package/lib/types/dsh-adapter/channel.d.ts +101 -2
  74. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  75. package/lib/types/dsh-adapter/channel.js +969 -93
  76. package/lib/types/dsh-adapter/compat/index.d.ts +8 -6
  77. package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -1
  78. package/lib/types/dsh-adapter/compat/index.js +8 -6
  79. package/lib/types/dsh-adapter/compat/sessionLog.d.ts +150 -0
  80. package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -1
  81. package/lib/types/dsh-adapter/compat/sessionLog.js +518 -41
  82. package/lib/types/dsh-adapter/contract.d.ts +1 -1
  83. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  84. package/lib/types/dsh-adapter/contract.js +1 -0
  85. package/lib/types/dsh-adapter/extension-events.d.ts +1 -1
  86. package/lib/types/dsh-adapter/extension-events.d.ts.map +1 -1
  87. package/lib/types/dsh-adapter/index.d.ts +10 -0
  88. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  89. package/lib/types/dsh-adapter/index.js +5 -0
  90. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  91. package/lib/types/dsh-adapter/plugin.js +317 -8
  92. package/lib/types/dsh-adapter/presets.d.ts +18 -0
  93. package/lib/types/dsh-adapter/presets.d.ts.map +1 -1
  94. package/lib/types/dsh-adapter/presets.js +31 -0
  95. package/lib/types/dsh-adapter/providerWizard.d.ts +29 -1
  96. package/lib/types/dsh-adapter/providerWizard.d.ts.map +1 -1
  97. package/lib/types/dsh-adapter/providerWizard.js +89 -5
  98. package/lib/types/dsh-adapter/questions.d.ts +19 -2
  99. package/lib/types/dsh-adapter/questions.d.ts.map +1 -1
  100. package/lib/types/dsh-adapter/questions.js +53 -10
  101. package/lib/types/dsh-adapter/recap.d.ts +49 -0
  102. package/lib/types/dsh-adapter/recap.d.ts.map +1 -0
  103. package/lib/types/dsh-adapter/recap.js +121 -0
  104. package/lib/types/dsh-adapter/sessionTree.d.ts +314 -0
  105. package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -0
  106. package/lib/types/dsh-adapter/sessionTree.js +954 -0
  107. package/lib/types/dsh-adapter/shortcuts.d.ts +15 -44
  108. package/lib/types/dsh-adapter/shortcuts.d.ts.map +1 -1
  109. package/lib/types/dsh-adapter/shortcuts.js +28 -165
  110. package/lib/types/dsh-adapter/types.d.ts +1 -1
  111. package/lib/types/dsh-adapter/types.d.ts.map +1 -1
  112. package/lib/types/herdr.js +1 -1
  113. package/lib/types/i18n.d.ts +604 -176
  114. package/lib/types/i18n.d.ts.map +1 -1
  115. package/lib/types/i18n.js +206 -72
  116. package/lib/types/ink/log-update.d.ts.map +1 -1
  117. package/lib/types/ink/log-update.js +21 -0
  118. package/lib/types/migrationPrefs.d.ts +60 -0
  119. package/lib/types/migrationPrefs.d.ts.map +1 -0
  120. package/lib/types/migrationPrefs.js +97 -0
  121. package/lib/types/modelGroups.d.ts +72 -0
  122. package/lib/types/modelGroups.d.ts.map +1 -0
  123. package/lib/types/modelGroups.js +97 -0
  124. package/lib/types/modelRecents.d.ts +39 -0
  125. package/lib/types/modelRecents.d.ts.map +1 -0
  126. package/lib/types/modelRecents.js +97 -0
  127. package/lib/types/native-ts/yoga-layout/index.d.ts +11 -0
  128. package/lib/types/native-ts/yoga-layout/index.d.ts.map +1 -1
  129. package/lib/types/native-ts/yoga-layout/index.js +31 -1
  130. package/lib/types/oauth.d.ts +15 -0
  131. package/lib/types/oauth.d.ts.map +1 -0
  132. package/lib/types/oauth.js +14 -0
  133. package/lib/types/plugin-spec/registry.d.ts +1 -1
  134. package/lib/types/plugin-spec/registry.js +1 -1
  135. package/lib/types/reload.d.ts +109 -0
  136. package/lib/types/reload.d.ts.map +1 -0
  137. package/lib/types/reload.js +118 -0
  138. package/lib/types/screens/Chat.d.ts +3 -1
  139. package/lib/types/screens/Chat.d.ts.map +1 -1
  140. package/lib/types/screens/Chat.js +588 -64
  141. package/lib/types/screens/SessionTree.d.ts +27 -0
  142. package/lib/types/screens/SessionTree.d.ts.map +1 -0
  143. package/lib/types/screens/SessionTree.js +555 -0
  144. package/lib/types/screens/StatusLine.d.ts +0 -9
  145. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  146. package/lib/types/screens/StatusLine.js +215 -52
  147. package/lib/types/screens/StatusMetrics.d.ts +35 -3
  148. package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
  149. package/lib/types/screens/StatusMetrics.js +63 -8
  150. package/lib/types/screens/chatOverlay.d.ts +17 -1
  151. package/lib/types/screens/chatOverlay.d.ts.map +1 -1
  152. package/lib/types/screens/chatOverlay.js +3 -1
  153. package/lib/types/tips.d.ts.map +1 -1
  154. package/lib/types/tips.js +22 -4
  155. package/lib/types/update.d.ts +159 -0
  156. package/lib/types/update.d.ts.map +1 -1
  157. package/lib/types/update.js +496 -30
  158. package/lib/types/utils/debug.d.ts +1 -1
  159. package/lib/types/utils/debug.js +3 -3
  160. package/lib/types/utils/fileTarget.d.ts +46 -0
  161. package/lib/types/utils/fileTarget.d.ts.map +1 -0
  162. package/lib/types/utils/fileTarget.js +178 -0
  163. package/lib/types/utils/keymap.d.ts +134 -0
  164. package/lib/types/utils/keymap.d.ts.map +1 -0
  165. package/lib/types/utils/keymap.js +311 -0
  166. package/lib/types/utils/mentions.d.ts +25 -2
  167. package/lib/types/utils/mentions.d.ts.map +1 -1
  168. package/lib/types/utils/mentions.js +69 -10
  169. package/lib/types/utils/openExternal.d.ts +50 -0
  170. package/lib/types/utils/openExternal.d.ts.map +1 -0
  171. package/lib/types/utils/openExternal.js +170 -0
  172. package/node_modules/@deepseek-harness-tui/dsh-auth/LICENSE +21 -0
  173. package/node_modules/@deepseek-harness-tui/dsh-auth/README.md +140 -0
  174. package/node_modules/@deepseek-harness-tui/dsh-auth/cordis.patch.yml +11 -0
  175. package/node_modules/@deepseek-harness-tui/dsh-auth/dsh-plugin.json +44 -0
  176. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/command.d.ts +14 -0
  177. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/command.js +67 -0
  178. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/credentials.d.ts +64 -0
  179. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/credentials.js +170 -0
  180. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/index.d.ts +79 -0
  181. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/index.js +196 -0
  182. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/interaction.d.ts +68 -0
  183. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/interaction.js +193 -0
  184. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/opener.d.ts +32 -0
  185. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/opener.js +101 -0
  186. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/profiles.d.ts +31 -0
  187. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/profiles.js +68 -0
  188. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/service.d.ts +69 -0
  189. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/service.js +129 -0
  190. package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +70 -0
  191. package/node_modules/@dsh-std/command/CHANGELOG.md +8 -8
  192. package/node_modules/@dsh-std/command/LICENSE +21 -21
  193. package/node_modules/@dsh-std/command/README.md +26 -26
  194. package/node_modules/@dsh-std/command/README.zh.md +28 -28
  195. package/node_modules/@dsh-std/command/lib/index.js.map +1 -1
  196. package/node_modules/@dsh-std/command/package.json +22 -22
  197. package/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
  198. package/node_modules/@dsh-std/connection/LICENSE +21 -21
  199. package/node_modules/@dsh-std/connection/README.md +42 -42
  200. package/node_modules/@dsh-std/connection/README.zh.md +42 -42
  201. package/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
  202. package/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  203. package/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
  204. package/node_modules/@dsh-std/connection/package.json +20 -20
  205. package/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  206. package/node_modules/@dsh-std/core/LICENSE +21 -21
  207. package/node_modules/@dsh-std/core/README.md +13 -13
  208. package/node_modules/@dsh-std/core/README.zh.md +13 -13
  209. package/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  210. package/node_modules/@dsh-std/core/package.json +21 -21
  211. package/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
  212. package/node_modules/@dsh-std/manifest/LICENSE +21 -21
  213. package/node_modules/@dsh-std/manifest/README.md +5 -5
  214. package/node_modules/@dsh-std/manifest/README.zh.md +5 -5
  215. package/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
  216. package/node_modules/@dsh-std/manifest/package.json +20 -20
  217. package/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
  218. package/node_modules/@dsh-std/messages/CHANGELOG.md +8 -8
  219. package/node_modules/@dsh-std/messages/LICENSE +21 -21
  220. package/node_modules/@dsh-std/messages/README.md +5 -5
  221. package/node_modules/@dsh-std/messages/README.zh.md +7 -7
  222. package/node_modules/@dsh-std/messages/lib/index.js.map +1 -1
  223. package/node_modules/@dsh-std/messages/package.json +20 -20
  224. package/node_modules/@dsh-std/messages/schema/message-observer-envelope-0.15.schema.json +54 -54
  225. package/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
  226. package/node_modules/@dsh-std/presentation/LICENSE +21 -21
  227. package/node_modules/@dsh-std/presentation/README.md +27 -27
  228. package/node_modules/@dsh-std/presentation/README.zh.md +29 -29
  229. package/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
  230. package/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
  231. package/node_modules/@dsh-std/presentation/package.json +25 -25
  232. package/node_modules/@dsh-std/storage/CHANGELOG.md +8 -8
  233. package/node_modules/@dsh-std/storage/LICENSE +21 -21
  234. package/node_modules/@dsh-std/storage/README.md +5 -5
  235. package/node_modules/@dsh-std/storage/README.zh.md +7 -7
  236. package/node_modules/@dsh-std/storage/lib/index.js.map +1 -1
  237. package/node_modules/@dsh-std/storage/package.json +20 -20
  238. package/node_modules/@dsh-std/storage/schema/local-storage-0.15.schema.json +56 -56
  239. package/package.json +17 -5
  240. package/presets/liangshen/.dsh-tui-managed.json +1 -1
  241. package/presets/liangshen/instruction-hint.mjs +8 -0
  242. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
  243. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/LICENSE +21 -21
  244. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.md +42 -42
  245. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.zh.md +42 -42
  246. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
  247. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  248. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
  249. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/package.json +20 -20
  250. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  251. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/LICENSE +21 -21
  252. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.md +13 -13
  253. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.zh.md +13 -13
  254. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  255. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/package.json +21 -21
  256. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
  257. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/LICENSE +21 -21
  258. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.md +5 -5
  259. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.zh.md +5 -5
  260. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
  261. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/package.json +20 -20
  262. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
  263. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
  264. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/LICENSE +21 -21
  265. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.md +27 -27
  266. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.zh.md +29 -29
  267. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
  268. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
  269. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/package.json +25 -25
  270. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  271. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/LICENSE +21 -21
  272. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.md +13 -13
  273. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.zh.md +13 -13
  274. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  275. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/package.json +21 -21
  276. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  277. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/LICENSE +21 -21
  278. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.md +13 -13
  279. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.zh.md +13 -13
  280. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  281. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/package.json +21 -21
  282. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  283. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/LICENSE +21 -21
  284. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.md +13 -13
  285. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.zh.md +13 -13
  286. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  287. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/package.json +21 -21
  288. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
  289. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/LICENSE +21 -21
  290. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.md +42 -42
  291. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.zh.md +42 -42
  292. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
  293. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  294. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
  295. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/package.json +20 -20
  296. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  297. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/LICENSE +21 -21
  298. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.md +13 -13
  299. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.zh.md +13 -13
  300. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  301. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/package.json +21 -21
  302. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  303. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/LICENSE +21 -21
  304. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.md +13 -13
  305. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.zh.md +13 -13
  306. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  307. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/package.json +21 -21
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ import type { Channel } from '../dsh-adapter/channel.js';
3
+ /**
4
+ * The session family tree — `/tree` as a screen of its own (pi's Session
5
+ * Tree over DSH's cross-session fork model).
6
+ *
7
+ * The tree shows every branch the conversation ever took: each rewind fork
8
+ * is stitched back onto the message it diverged from, the live path is
9
+ * marked with `•`, and every other branch stays reachable. Picking a node
10
+ * offers the ways DSH can act on it — rewind (drop the turn, edit its
11
+ * prompt), fork (keep the entry, branch here), adopt (switch to a dead
12
+ * branch whole).
13
+ *
14
+ * Interaction is mouse-first but keyboard-complete: hovering a row shows its
15
+ * full text in the preview pane, clicking it opens the action menu, and the
16
+ * same actions sit on Enter / Ctrl+F / Ctrl+B for the keyboard path. The
17
+ * confirm seat stands between every high-risk action and the fork.
18
+ */
19
+ export declare function SessionTree({ channel, currentSessionId, onClose, onRestoreText, }: {
20
+ channel: Channel;
21
+ /** Live session id at open time (adopt-live refusal, menu labels). */
22
+ currentSessionId: string;
23
+ onClose: () => void;
24
+ /** The dropped turn's prompt goes back into the input for re-editing. */
25
+ onRestoreText: (text: string) => void;
26
+ }): React.ReactNode;
27
+ //# sourceMappingURL=SessionTree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionTree.d.ts","sourceRoot":"","sources":["../../../src/screens/SessionTree.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAUzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAqIxD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,gBAAgB,EAChB,OAAO,EACP,aAAa,GACd,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,sEAAsE;IACtE,gBAAgB,EAAE,MAAM,CAAA;IACxB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,yEAAyE;IACzE,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACtC,GAAG,KAAK,CAAC,SAAS,CAselB"}
@@ -0,0 +1,555 @@
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 { Divider } from '../components/design-system/Divider.js';
5
+ import { HintLine } from '../components/design-system/HintLine.js';
6
+ import { SearchBox } from '../components/SearchBox.js';
7
+ import { useTerminalFocus } from '../ink/hooks/use-terminal-focus.js';
8
+ import { isMod, isPlainReturn, modLabel } from '../utils/modifiers.js';
9
+ import { spreadRow, tailWidth, truncateWidth, wrapWidth } from '../sessions/format.js';
10
+ import { stringWidth } from '../ink/stringWidth.js';
11
+ import { t } from '../i18n.js';
12
+ import { droppedTurnInfo, filterTree, flattenTree, nearestVisibleIndex, TREE_FILTERS, } from '../dsh-adapter/sessionTree.js';
13
+ /** Local HH:MM (or MM/DD HH:MM when older than this year). */
14
+ function formatTime(at, now) {
15
+ const date = new Date(at);
16
+ const pad = (n) => String(n).padStart(2, '0');
17
+ const time = `${pad(date.getHours())}:${pad(date.getMinutes())}`;
18
+ const sameYear = new Date(now).getFullYear() === date.getFullYear();
19
+ return sameYear ? time : `${pad(date.getMonth() + 1)}/${pad(date.getDate())} ${time}`;
20
+ }
21
+ /** A thrown value's message, for a notification that has to say something. */
22
+ function message(error) {
23
+ return error instanceof Error ? error.message : String(error);
24
+ }
25
+ /** Rendered width of a hint: `HintLine` strips the `**` emphasis markers. */
26
+ function hintWidth(text) {
27
+ return stringWidth(text.replace(/\*\*/gu, ''));
28
+ }
29
+ /** The widest hint that fits; cut only when even the shortest will not. */
30
+ function fitHint(candidates, budget) {
31
+ for (const candidate of candidates) {
32
+ if (hintWidth(candidate) <= budget)
33
+ return candidate;
34
+ }
35
+ return truncateWidth((candidates[candidates.length - 1] ?? '').replace(/\*\*/gu, ''), budget);
36
+ }
37
+ /** Terminal cells of each kind prefix shown before the entry text. */
38
+ const KIND_PREFIX = {
39
+ user: { text: 'user: ', color: 'suggestion' },
40
+ assistant: { text: 'assistant: ', color: 'success' },
41
+ tool: { text: '', color: 'subtle' },
42
+ compact: { text: '[compact] ', color: 'planMode' },
43
+ interrupt: { text: '', color: 'warning' },
44
+ notice: { text: '', color: 'warning' },
45
+ };
46
+ /** Tool outcome glyph appended to a tool row. */
47
+ function toolGlyph(entry) {
48
+ if (entry.toolStatus === 'ok')
49
+ return { glyph: ' ✓', color: 'success' };
50
+ if (entry.toolStatus === 'error')
51
+ return { glyph: ' ✗', color: 'error' };
52
+ if (entry.toolStatus === 'running')
53
+ return { glyph: ' …', color: 'warning' };
54
+ return undefined;
55
+ }
56
+ /**
57
+ * pi's tree prefix: gutters at recorded positions, connector at indent-1.
58
+ * Each indent level is 3 cells (`│ `, `├─ `, `└─ `).
59
+ */
60
+ function treePrefix(flatNode) {
61
+ const displayIndent = flatNode.multipleRoots ? Math.max(0, flatNode.indent - 1) : flatNode.indent;
62
+ const hasConnector = flatNode.showConnector && !flatNode.isVirtualRootChild;
63
+ const connectorPosition = hasConnector ? displayIndent - 1 : -1;
64
+ const chars = [];
65
+ for (let i = 0; i < displayIndent * 3; i++) {
66
+ const level = Math.floor(i / 3);
67
+ const posInLevel = i % 3;
68
+ const gutter = flatNode.gutters.find(g => g.position === level);
69
+ if (gutter !== undefined) {
70
+ chars.push(posInLevel === 0 ? (gutter.show ? '│' : ' ') : ' ');
71
+ }
72
+ else if (level === connectorPosition) {
73
+ if (posInLevel === 0)
74
+ chars.push(flatNode.isLast ? '└' : '├');
75
+ else if (posInLevel === 1)
76
+ chars.push('─');
77
+ else
78
+ chars.push(' ');
79
+ }
80
+ else {
81
+ chars.push(' ');
82
+ }
83
+ }
84
+ return chars.join('');
85
+ }
86
+ /**
87
+ * Keep the LAST `budget` display cells of a prefix, prefixing '…' when any
88
+ * level was cut — narrow terminals sacrifice the oldest ancestors, never the
89
+ * branch geometry next to the entry.
90
+ */
91
+ function clampPrefix(prefix, budget) {
92
+ if (stringWidth(prefix) <= budget)
93
+ return prefix;
94
+ if (budget <= 1)
95
+ return '…';
96
+ return `…${tailWidth(prefix, budget - 1)}`;
97
+ }
98
+ /** Rows the layout cannot do without: header, search box, hints. */
99
+ const MANDATORY_LINES = 3;
100
+ /** Both dividers, in the order they earn their row (header rule first). */
101
+ const RULE_PRIORITY = [0, 1];
102
+ /** Width from which the preview pane sits beside the list instead of below. */
103
+ const SPLIT_MIN_COLUMNS = 100;
104
+ /** Lines the bottom preview block may take on narrow terminals. */
105
+ const PREVIEW_BLOCK_LINES = 5;
106
+ /**
107
+ * The session family tree — `/tree` as a screen of its own (pi's Session
108
+ * Tree over DSH's cross-session fork model).
109
+ *
110
+ * The tree shows every branch the conversation ever took: each rewind fork
111
+ * is stitched back onto the message it diverged from, the live path is
112
+ * marked with `•`, and every other branch stays reachable. Picking a node
113
+ * offers the ways DSH can act on it — rewind (drop the turn, edit its
114
+ * prompt), fork (keep the entry, branch here), adopt (switch to a dead
115
+ * branch whole).
116
+ *
117
+ * Interaction is mouse-first but keyboard-complete: hovering a row shows its
118
+ * full text in the preview pane, clicking it opens the action menu, and the
119
+ * same actions sit on Enter / Ctrl+F / Ctrl+B for the keyboard path. The
120
+ * confirm seat stands between every high-risk action and the fork.
121
+ */
122
+ export function SessionTree({ channel, currentSessionId, onClose, onRestoreText, }) {
123
+ const { columns, rows } = useTerminalSize();
124
+ const isTerminalFocused = useTerminalFocus();
125
+ const [data, setData] = React.useState(null);
126
+ const [loading, setLoading] = React.useState(true);
127
+ /** A rewind/fork/adopt is in flight — the seat stays up until it settles. */
128
+ const [busy, setBusy] = React.useState(false);
129
+ const [notice, setNotice] = React.useState();
130
+ // The cursor is a node id, not an index: filters and searches rebuild the
131
+ // row list, and an index would silently land on a different node.
132
+ const [selectedId, setSelectedId] = React.useState(null);
133
+ const [filter, setFilter] = React.useState('default');
134
+ const [query, setQuery] = React.useState('');
135
+ /** The hovered node id — drives the preview pane alongside the cursor. */
136
+ const [hoverId, setHoverId] = React.useState(null);
137
+ const [menuNodeId, setMenuNodeId] = React.useState(null);
138
+ const [menuIndex, setMenuIndex] = React.useState(0);
139
+ const [confirmHovered, setConfirmHovered] = React.useState(false);
140
+ const [confirmState, setConfirmState] = React.useState(null);
141
+ // React batches every parsed key from one stdin chunk; actions lock in a
142
+ // ref so a repeated Enter cannot start the same async operation twice.
143
+ const actionPendingRef = React.useRef(false);
144
+ // ── Load ────────────────────────────────────────────────────────────────
145
+ // A build that settles null/undefined closes the screen: the channel
146
+ // already toasted the reason (persistence absent) or the live session
147
+ // swapped mid-build (silent by design — the reopened tree rebuilds on the
148
+ // new session).
149
+ React.useEffect(() => {
150
+ let live = true;
151
+ void channel
152
+ .buildSessionTree()
153
+ .then(result => (live ? result : undefined))
154
+ .catch(() => undefined)
155
+ .then(result => {
156
+ if (!live)
157
+ return;
158
+ if (result === null || result === undefined) {
159
+ onClose();
160
+ return;
161
+ }
162
+ setData(result);
163
+ setLoading(false);
164
+ });
165
+ return () => {
166
+ live = false;
167
+ };
168
+ }, [channel, onClose]);
169
+ // ── Derived view ────────────────────────────────────────────────────────
170
+ const full = React.useMemo(() => (data === null ? [] : flattenTree(data.roots, data.activeLeafId)), [data]);
171
+ const visible = React.useMemo(() => (data === null ? [] : filterTree(full, data.activeLeafId, filter, query)), [data, full, filter, query]);
172
+ const focusIndex = React.useMemo(() => {
173
+ if (visible.length === 0)
174
+ return 0;
175
+ return nearestVisibleIndex(visible, full, selectedId ?? data?.activeLeafId ?? null);
176
+ }, [visible, full, selectedId, data?.activeLeafId]);
177
+ const focusedNode = visible[focusIndex];
178
+ const focusedEntry = focusedNode?.node.entry ?? null;
179
+ // The menu rides the PICKED node id (not the cursor): moving the cursor
180
+ // while the menu is open must not retarget an action.
181
+ const menuNode = menuNodeId === null
182
+ ? undefined
183
+ : visible.find(n => n.node.id === menuNodeId) ?? full.find(n => n.node.id === menuNodeId);
184
+ const menuEntry = menuNode?.node.entry ?? null;
185
+ const menuOpen = menuNode !== undefined && menuEntry !== null;
186
+ const seat = confirmState !== null ? 'confirm' : menuOpen ? 'menu' : 'tree';
187
+ // Preview target: the hovered row wins (that is what the eye is asking
188
+ // about), the focused row backs it up so keyboard users see one too.
189
+ const previewNode = (hoverId !== null ? visible.find(n => n.node.id === hoverId) : undefined) ?? focusedNode;
190
+ const previewEntry = previewNode?.node.entry ?? null;
191
+ // ── Actions ─────────────────────────────────────────────────────────────
192
+ /** Pre-validate a rewind pick the way rewindToNode will refuse it. */
193
+ const rewindBlockedReason = (entry) => {
194
+ if (entry.firstTurn === true && entry.kind === 'user')
195
+ return t('tree-first-message');
196
+ return undefined;
197
+ };
198
+ /** Build the click menu's options for one entry. */
199
+ const menuOptionsFor = (entry) => {
200
+ const options = [];
201
+ const blocked = rewindBlockedReason(entry);
202
+ options.push({
203
+ id: 'rewind',
204
+ label: t('tree-menu-rewind'),
205
+ detail: blocked ?? t('tree-menu-rewind-detail'),
206
+ ...(blocked !== undefined ? { disabled: true } : {}),
207
+ });
208
+ options.push({ id: 'fork', label: t('tree-menu-fork'), detail: t('tree-menu-fork-detail') });
209
+ const tip = data?.rewindFacts.get(entry.sessionId)?.tipBoundary;
210
+ if (entry.sessionId !== currentSessionId) {
211
+ options.push(tip === undefined
212
+ ? { id: 'adopt', label: t('tree-menu-adopt'), detail: t('tree-adopt-unavailable'), disabled: true }
213
+ : { id: 'adopt', label: t('tree-menu-adopt'), detail: t('tree-menu-adopt-detail') });
214
+ }
215
+ options.push({ id: 'cancel', label: t('tree-menu-cancel'), detail: '' });
216
+ return options;
217
+ };
218
+ const options = menuOpen && menuEntry !== null ? menuOptionsFor(menuEntry) : [];
219
+ const runAction = (action) => {
220
+ if (actionPendingRef.current)
221
+ return;
222
+ actionPendingRef.current = true;
223
+ void action().finally(() => {
224
+ actionPendingRef.current = false;
225
+ });
226
+ };
227
+ /**
228
+ * Execute a rewind/fork at an entry (menu rows, Ctrl+F). The seat stays up
229
+ * while the swap runs; success closes the screen and hands the dropped
230
+ * turn's prompt back to the input.
231
+ */
232
+ const executeAt = (entry, mode) => {
233
+ runAction(async () => {
234
+ setBusy(true);
235
+ try {
236
+ const text = await channel.rewindToNode(entry.sessionId, entry.seq, mode);
237
+ if (text === null) {
238
+ // The channel notified the transcript (hidden behind this screen),
239
+ // so repeat the refusal on screen and stay put.
240
+ setNotice({ text: t('tree-refused'), tone: 'error' });
241
+ setBusy(false);
242
+ return;
243
+ }
244
+ if (text !== '')
245
+ onRestoreText(text);
246
+ channel.notify(mode === 'fork' ? t('tree-forked') : t('tree-rewound'));
247
+ onClose();
248
+ }
249
+ catch (error) {
250
+ setNotice({ text: t('tree-rewind-failed', { message: message(error) }), tone: 'error' });
251
+ setBusy(false);
252
+ }
253
+ });
254
+ };
255
+ /** Adopt = fork the branch at its tip with the whole log kept. */
256
+ const executeAdopt = (entry, tipSeq) => {
257
+ runAction(async () => {
258
+ setBusy(true);
259
+ try {
260
+ const text = await channel.rewindToNode(entry.sessionId, tipSeq, 'rewind');
261
+ if (text === null) {
262
+ setNotice({ text: t('tree-refused'), tone: 'error' });
263
+ setBusy(false);
264
+ return;
265
+ }
266
+ channel.notify(t('tree-adopted'));
267
+ onClose();
268
+ }
269
+ catch (error) {
270
+ setNotice({ text: t('tree-rewind-failed', { message: message(error) }), tone: 'error' });
271
+ setBusy(false);
272
+ }
273
+ });
274
+ };
275
+ /** A rewind pick (Enter path and the menu's rewind option): confirm seat. */
276
+ const askRewind = (entry) => {
277
+ const blocked = rewindBlockedReason(entry);
278
+ if (blocked !== undefined) {
279
+ setNotice({ text: blocked, tone: 'error' });
280
+ return;
281
+ }
282
+ const drop = data === null ? undefined : droppedTurnInfo(data, entry);
283
+ setConfirmState({
284
+ kind: 'rewind',
285
+ entry,
286
+ ...(drop?.coversBranch === true ? { dropsBranch: true } : {}),
287
+ ...(drop !== undefined ? { droppedEntries: drop.droppedEntries } : {}),
288
+ });
289
+ };
290
+ /** Ctrl+B (and the menu's adopt option): the confirm seat. */
291
+ const askAdopt = (entry) => {
292
+ if (entry.sessionId === currentSessionId) {
293
+ setNotice({ text: t('tree-adopt-live'), tone: 'info' });
294
+ return;
295
+ }
296
+ const tip = data?.rewindFacts.get(entry.sessionId)?.tipBoundary;
297
+ if (tip === undefined) {
298
+ setNotice({ text: t('tree-adopt-unavailable'), tone: 'error' });
299
+ return;
300
+ }
301
+ setConfirmState({ kind: 'adopt', entry, tipSeq: tip });
302
+ };
303
+ const performConfirm = (confirm) => {
304
+ setConfirmState(null);
305
+ if (confirm.kind === 'adopt') {
306
+ if (confirm.tipSeq !== undefined)
307
+ executeAdopt(confirm.entry, confirm.tipSeq);
308
+ return;
309
+ }
310
+ executeAt(confirm.entry, 'rewind');
311
+ };
312
+ /** Run one menu option (click path and Enter path share this). */
313
+ const runMenuOption = (option) => {
314
+ if (option.disabled === true || !menuOpen || menuEntry === null)
315
+ return;
316
+ const entry = menuEntry;
317
+ setMenuNodeId(null);
318
+ if (option.id === 'cancel')
319
+ return;
320
+ if (option.id === 'rewind')
321
+ askRewind(entry);
322
+ else if (option.id === 'fork')
323
+ executeAt(entry, 'fork');
324
+ else
325
+ askAdopt(entry);
326
+ };
327
+ // ── Keyboard ────────────────────────────────────────────────────────────
328
+ // Keys are read through refs for the same reason SessionBrowser does it:
329
+ // several key events can arrive in one stdin chunk before React re-renders.
330
+ const focusIndexRef = React.useRef(focusIndex);
331
+ focusIndexRef.current = focusIndex;
332
+ const visibleRef = React.useRef(visible);
333
+ visibleRef.current = visible;
334
+ const listHeightRef = React.useRef(1);
335
+ const step = (by, times = 1, wrap = true) => {
336
+ const list = visibleRef.current;
337
+ if (list.length === 0)
338
+ return;
339
+ let at = focusIndexRef.current;
340
+ for (let taken = 0; taken < times; taken++) {
341
+ at = at + by;
342
+ if (at < 0)
343
+ at = wrap ? list.length - 1 : 0;
344
+ if (at >= list.length)
345
+ at = wrap ? 0 : list.length - 1;
346
+ }
347
+ focusIndexRef.current = at;
348
+ setSelectedId(list[at]?.node.id ?? null);
349
+ };
350
+ useInput((input, key) => {
351
+ // While an action is in flight the seat swallows every key — closing now
352
+ // would drop the user back into a half-swapped session.
353
+ if (busy)
354
+ return;
355
+ if (notice !== undefined)
356
+ setNotice(undefined);
357
+ if (seat === 'confirm' && confirmState !== null) {
358
+ if (isPlainReturn(key))
359
+ performConfirm(confirmState);
360
+ else if (key.escape)
361
+ setConfirmState(null);
362
+ return;
363
+ }
364
+ if (seat === 'menu') {
365
+ if (key.upArrow)
366
+ setMenuIndex(index => wrapIndex(index, -1, options.length));
367
+ else if (key.downArrow)
368
+ setMenuIndex(index => wrapIndex(index, 1, options.length));
369
+ else if (key.escape)
370
+ setMenuNodeId(null);
371
+ else if (isPlainReturn(key)) {
372
+ const option = options[menuIndex];
373
+ if (option !== undefined)
374
+ runMenuOption(option);
375
+ }
376
+ else if (!isMod(key) && !key.meta && input) {
377
+ const lower = input.toLowerCase();
378
+ const hit = options.find(option => option.id !== 'cancel' && option.id.startsWith(lower));
379
+ if (hit !== undefined)
380
+ runMenuOption(hit);
381
+ }
382
+ return;
383
+ }
384
+ if (key.upArrow)
385
+ step(-1);
386
+ else if (key.downArrow)
387
+ step(1);
388
+ else if (key.wheelUp)
389
+ step(-1, 1, false);
390
+ else if (key.wheelDown)
391
+ step(1, 1, false);
392
+ else if (key.pageUp || key.leftArrow)
393
+ step(-1, Math.max(1, Math.floor(listHeightRef.current / 2)));
394
+ else if (key.pageDown || key.rightArrow)
395
+ step(1, Math.max(1, Math.floor(listHeightRef.current / 2)));
396
+ else if (key.escape) {
397
+ // Esc backs out one layer at a time: a live query first, the screen
398
+ // second — closing on the first Esc would discard a search still being
399
+ // refined.
400
+ if (query !== '')
401
+ setQuery('');
402
+ else
403
+ onClose();
404
+ }
405
+ else if (isPlainReturn(key)) {
406
+ if (focusedEntry !== null && focusedNode !== undefined) {
407
+ setSelectedId(focusedNode.node.id);
408
+ setMenuNodeId(focusedNode.node.id);
409
+ setMenuIndex(0);
410
+ }
411
+ }
412
+ else if (isMod(key) && input === 'o') {
413
+ const index = TREE_FILTERS.indexOf(filter);
414
+ setFilter(TREE_FILTERS[(index + 1) % TREE_FILTERS.length] ?? 'default');
415
+ }
416
+ else if (isMod(key) && input === 'f' && focusedEntry !== null) {
417
+ executeAt(focusedEntry, 'fork');
418
+ }
419
+ else if (isMod(key) && input === 'b' && focusedEntry !== null) {
420
+ askAdopt(focusedEntry);
421
+ }
422
+ else if (key.backspace || key.delete) {
423
+ setQuery(text => text.slice(0, -1));
424
+ }
425
+ else if (!isMod(key) && !key.meta && !key.super && input && !key.return) {
426
+ // Only real characters reach the query — anything else the terminal
427
+ // delivers would be typed into the search invisibly.
428
+ const typed = input.replace(/\p{Cc}/gu, '');
429
+ if (typed.length > 0)
430
+ setQuery(text => text + typed);
431
+ }
432
+ });
433
+ // ── Layout arithmetic ───────────────────────────────────────────────────
434
+ const inputBudget = Math.max(0, columns - 2);
435
+ const menuLines = seat === 'menu' ? 1 + options.length : 0;
436
+ const confirmLines = confirmState === null ? 0 : 1 + (confirmState.dropsBranch === true ? 1 : 0);
437
+ const previewBlock = seat === 'tree' && previewEntry !== null && columns < SPLIT_MIN_COLUMNS && hoverId !== null
438
+ ? PREVIEW_BLOCK_LINES
439
+ : 0;
440
+ const extraLines = (notice === undefined ? 0 : 1) + menuLines + confirmLines + previewBlock;
441
+ const ruleBudget = Math.max(0, Math.min(RULE_PRIORITY.length, rows - MANDATORY_LINES - extraLines));
442
+ const rules = new Set(RULE_PRIORITY.slice(0, ruleBudget));
443
+ const listHeight = Math.max(0, rows - MANDATORY_LINES - extraLines - rules.size);
444
+ listHeightRef.current = listHeight;
445
+ const splitPreview = seat === 'tree' && previewEntry !== null && columns >= SPLIT_MIN_COLUMNS;
446
+ const previewWidth = splitPreview ? Math.min(52, Math.floor(columns * 0.38)) : columns;
447
+ const listWidth = Math.max(20, columns - (splitPreview ? previewWidth : 0));
448
+ // Cursor-centered window over single-line rows.
449
+ const windowStart = visible.length <= listHeight
450
+ ? 0
451
+ : Math.max(0, Math.min(focusIndex - Math.floor(listHeight / 2), visible.length - listHeight));
452
+ const windowed = visible.slice(windowStart, windowStart + Math.max(0, listHeight));
453
+ const heading = ` ${t('tree-title')}`;
454
+ const right = [
455
+ `${focusIndex + 1}/${visible.length}`,
456
+ t(`tree-filter-${filter}`),
457
+ `${data?.sessionCount ?? 0} ${t('tree-sessions')}`,
458
+ ...(data?.truncated === true ? [t('tree-truncated')] : []),
459
+ ].join(' · ');
460
+ const header = spreadRow(heading, right, Math.max(0, columns - 1));
461
+ const hint = seat === 'confirm'
462
+ ? fitHint([t('tree-hint-confirm')], inputBudget)
463
+ : seat === 'menu'
464
+ ? fitHint([t('tree-hint-menu')], inputBudget)
465
+ : fitHint([t('tree-hint', { mod: modLabel }), t('tree-hint-short')], inputBudget);
466
+ // ── Loading / busy seats ────────────────────────────────────────────────
467
+ if (loading || busy) {
468
+ return (_jsxs(Box, { flexDirection: "column", width: columns, height: rows, children: [_jsx(Box, { flexShrink: 0, children: _jsx(Text, { color: "remember", bold: true, children: truncateWidth(` ${t('tree-title')}`, inputBudget) }) }), rules.has(0) && (_jsx(Box, { flexShrink: 0, children: _jsx(Divider, { width: columns }) })), _jsx(Box, { flexShrink: 0, children: _jsx(Text, { dimColor: true, italic: true, children: ` ${truncateWidth(busy ? t('tree-rewinding') : t('tree-loading'), inputBudget)}` }) })] }));
469
+ }
470
+ // ── Render ──────────────────────────────────────────────────────────────
471
+ return (_jsxs(Box, { flexDirection: "column", width: columns, height: rows, children: [_jsxs(Box, { flexShrink: 0, children: [_jsx(Text, { color: "remember", bold: true, children: header.left }), _jsx(Text, { dimColor: true, children: `${' '.repeat(header.gap)}${header.right}` })] }), rules.has(0) && (_jsx(Box, { flexShrink: 0, children: _jsx(Divider, { width: columns }) })), _jsx(Box, { flexShrink: 0, children: _jsx(SearchBox, { query: tailWidth(query, inputBudget), isFocused: seat === 'tree', isTerminalFocused: isTerminalFocused, placeholder: truncateWidth(t('tree-search'), inputBudget), borderless: true }) }), _jsxs(Box, { flexGrow: 1, flexShrink: 1, children: [_jsxs(Box, { flexDirection: "column", width: listWidth, height: listHeight, flexShrink: 0, children: [visible.length === 0 && (_jsx(Text, { dimColor: true, italic: true, children: ` ${truncateWidth(t('tree-empty'), Math.max(0, listWidth - 2))}` })), windowed.map((flatNode, index) => (_jsx(TreeRow, { flatNode: flatNode, meta: data?.sessions.get(flatNode.node.sessionId), liveSessionId: currentSessionId, width: listWidth, focused: windowStart + index === focusIndex, onActivePath: data?.activePath.has(flatNode.node.id) === true, onHover: setHoverId, onClick: () => {
472
+ // Click = focus + open the action menu (the mouse path to
473
+ // every action this screen offers); the menu's own rows
474
+ // execute.
475
+ setSelectedId(flatNode.node.id);
476
+ setMenuNodeId(flatNode.node.id);
477
+ setMenuIndex(0);
478
+ } }, flatNode.node.id)))] }), splitPreview && previewEntry !== null && (_jsx(PreviewPane, { entry: previewEntry, meta: data?.sessions.get(previewEntry.sessionId), width: previewWidth, height: listHeight, liveSessionId: currentSessionId, now: Date.now() }))] }), previewBlock > 0 && previewEntry !== null && (_jsx(PreviewPane, { entry: previewEntry, meta: data?.sessions.get(previewEntry.sessionId), width: columns, height: previewBlock, liveSessionId: currentSessionId, now: Date.now(), compact: true })), notice !== undefined && (_jsx(Box, { flexShrink: 0, children: _jsx(Text, { color: notice.tone === 'error' ? 'error' : 'success', children: ` ${truncateWidth(notice.text, inputBudget)}` }) })), seat === 'menu' && menuEntry !== null && (_jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [_jsx(Box, { flexShrink: 0, children: _jsx(Text, { color: "remember", children: ` ${truncateWidth(`❰ ${menuEntry.text}`, inputBudget)}` }) }), options.map((option, index) => (_jsx(MenuOptionRow, { option: option, highlighted: index === menuIndex, width: inputBudget, onClick: () => {
479
+ setMenuIndex(index);
480
+ runMenuOption(option);
481
+ }, onHover: () => setMenuIndex(index) }, option.id)))] })), seat === 'confirm' && confirmState !== null && (_jsxs(Box, { flexShrink: 0, flexDirection: "column",
482
+ // 点击确认行 = 确认执行(与 Enter 同路径);取消保留键盘 Esc,防误点
483
+ onClick: () => performConfirm(confirmState), onMouseEnter: () => setConfirmHovered(true), onMouseLeave: () => setConfirmHovered(false), backgroundColor: confirmHovered ? 'userMessageBackgroundHover' : undefined, children: [_jsx(Text, { color: "warning", children: ` ${truncateWidth(confirmState.kind === 'adopt'
484
+ ? t('tree-confirm-adopt', { text: confirmState.entry.text })
485
+ : confirmState.droppedEntries !== undefined && confirmState.droppedEntries > 0
486
+ ? t('tree-confirm-drop', { text: confirmState.entry.text, n: confirmState.droppedEntries })
487
+ : t('tree-confirm-rewind', { text: confirmState.entry.text }), inputBudget)}` }), confirmState.dropsBranch === true && (_jsx(Text, { color: "error", children: ` ${truncateWidth(t('tree-confirm-drops-branch'), inputBudget)}` }))] })), rules.has(1) && (_jsx(Box, { flexShrink: 0, children: _jsx(Divider, { width: columns }) })), _jsx(Box, { flexShrink: 0, children: _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: hint }) }) })] }));
488
+ }
489
+ /** Index wrap helper for the menu cursor. */
490
+ function wrapIndex(current, by, count) {
491
+ if (count <= 0)
492
+ return 0;
493
+ return (current + by + count) % count;
494
+ }
495
+ /**
496
+ * One tree row: focus pointer, tree-drawing prefix, active-path bullet,
497
+ * branch badge, then the entry text in its kind's colours. Hover highlights
498
+ * the row and drives the preview pane; click opens the action menu.
499
+ */
500
+ function TreeRow({ flatNode, meta, liveSessionId, width, focused, onActivePath, onHover, onClick, }) {
501
+ const [hovered, setHovered] = React.useState(false);
502
+ const entry = flatNode.node.entry;
503
+ if (entry === null) {
504
+ // Placeholder rows: an empty fork, an unreadable log, an unloaded one.
505
+ // They carry no action, but keep the branch structure visible.
506
+ const label = meta?.unreadable === true
507
+ ? t('tree-unreadable')
508
+ : meta?.unloaded === true
509
+ ? t('tree-unloaded')
510
+ : t('tree-empty-fork');
511
+ return (_jsxs(Box, { flexShrink: 0, onClick: onClick, onMouseEnter: () => {
512
+ setHovered(true);
513
+ onHover(null);
514
+ }, onMouseLeave: () => setHovered(false), backgroundColor: hovered ? 'userMessageBackgroundHover' : undefined, children: [_jsx(Text, { color: "subtle", children: ' ' }), _jsx(Text, { dimColor: true, children: clampPrefix(treePrefix(flatNode), Math.max(0, width - 4)) }), _jsx(Text, { dimColor: true, italic: true, children: truncateWidth(`⎇ ${label}`, Math.max(0, width - 6)) })] }));
515
+ }
516
+ const kind = KIND_PREFIX[entry.kind];
517
+ const glyph = entry.kind === 'tool' ? toolGlyph(entry) : undefined;
518
+ // Branch badge: the first row of a session chain names the branch it
519
+ // starts — the live session wears its own mark.
520
+ const badge = flatNode.node.branchHead
521
+ ? `${flatNode.node.sessionId === liveSessionId ? '●' : '⎇'} ${truncateWidth(meta?.title ?? flatNode.node.sessionId.slice(0, 8), 16)} › `
522
+ : '';
523
+ const budget = Math.max(4, width - 2 - stringWidth(clampPrefix(treePrefix(flatNode), Math.max(0, width - 8))) - (onActivePath ? 2 : 0) - stringWidth(badge) - stringWidth(kind.text) - (glyph === undefined ? 0 : 2));
524
+ return (_jsxs(Box, { flexShrink: 0, onClick: onClick, onMouseEnter: () => {
525
+ setHovered(true);
526
+ onHover(flatNode.node.id);
527
+ }, onMouseLeave: () => {
528
+ setHovered(false);
529
+ onHover(null);
530
+ }, backgroundColor: hovered && !focused ? 'userMessageBackgroundHover' : undefined, children: [_jsx(Text, { color: focused ? 'suggestion' : 'subtle', children: focused ? '❯ ' : ' ' }), _jsx(Text, { dimColor: true, children: clampPrefix(treePrefix(flatNode), Math.max(0, width - 8)) }), onActivePath && _jsx(Text, { color: "suggestion", children: '• ' }), badge !== '' && _jsx(Text, { color: flatNode.node.sessionId === liveSessionId ? 'remember' : 'planMode', dimColor: true, children: badge }), kind.text !== '' && (_jsx(Text, { color: entry.label === 'aborted' ? 'warning' : kind.color, children: kind.text })), _jsx(Text, { color: entry.kind === 'interrupt' || entry.kind === 'notice' ? 'warning' : entry.kind === 'tool' ? 'subtle' : undefined, bold: focused, dimColor: entry.kind === 'tool', children: truncateWidth(`${entry.text}${entry.label === 'aborted' ? ` (${entry.label})` : ''}`, budget) }), glyph !== undefined && _jsx(Text, { color: glyph.color, children: glyph.glyph })] }));
531
+ }
532
+ /** One option row of the click menu: marker, label, detail. */
533
+ function MenuOptionRow({ option, highlighted, width, onClick, onHover, }) {
534
+ const dim = option.disabled === true;
535
+ const labelWidth = 14;
536
+ const detailBudget = Math.max(0, width - 4 - labelWidth);
537
+ return (_jsxs(Box, { flexShrink: 0, onClick: dim ? undefined : onClick, onMouseEnter: dim ? undefined : onHover, backgroundColor: highlighted && !dim ? 'userMessageBackgroundHover' : undefined, children: [_jsx(Text, { color: highlighted ? 'suggestion' : 'subtle', children: highlighted ? '❯ ' : ' ' }), _jsx(Text, { color: dim ? 'inactive' : option.id === 'rewind' ? 'warning' : option.id === 'fork' ? 'remember' : option.id === 'adopt' ? 'planMode' : 'subtle', bold: highlighted && !dim, children: truncateWidth(option.label, labelWidth) }), _jsx(Text, { dimColor: true, children: ` ${truncateWidth(option.detail, detailBudget)}` })] }));
538
+ }
539
+ /**
540
+ * The preview pane: the hovered (or focused) entry's full text, wrapped,
541
+ * with the facts that place it — kind, time, branch, seq.
542
+ */
543
+ function PreviewPane({ entry, meta, width, height, liveSessionId, now, compact, }) {
544
+ const bodyWidth = Math.max(8, width - 2);
545
+ const kindLabel = t(`tree-kind-${entry.kind}`);
546
+ const head = `${kindLabel} · ${formatTime(entry.time, now)}`;
547
+ const lines = wrapWidth(entry.text, bodyWidth).slice(0, Math.max(0, height - (compact === true ? 2 : 4)));
548
+ const cut = wrapWidth(entry.text, bodyWidth).length > lines.length;
549
+ const branch = entry.sessionId === liveSessionId
550
+ ? t('tree-branch-live')
551
+ : meta?.title !== undefined
552
+ ? truncateWidth(meta.title, Math.max(0, bodyWidth - head.length - 3))
553
+ : entry.sessionId.slice(0, 8);
554
+ return (_jsxs(Box, { flexDirection: "column", width: width, height: height, flexShrink: 0, children: [!compact && (_jsx(Box, { flexShrink: 0, children: _jsx(Text, { color: "remember", bold: true, children: ` ${truncateWidth(t('tree-preview-title'), Math.max(0, width - 1))}` }) })), _jsxs(Box, { flexShrink: 0, children: [_jsx(Text, { color: "planMode", children: ` ${truncateWidth(head, Math.max(0, width - 1))}` }), _jsx(Text, { dimColor: true, children: ` ${truncateWidth(branch, Math.max(0, width - 1 - stringWidth(head)))}` })] }), !compact && _jsx(Divider, { width: width }), lines.map((line, index) => (_jsx(Box, { flexShrink: 0, children: _jsx(Text, { children: ` ${truncateWidth(line, bodyWidth)}` }) }, index))), cut && (_jsx(Box, { flexShrink: 0, children: _jsx(Text, { dimColor: true, children: ` ${'…'}` }) }))] }));
555
+ }
@@ -1,15 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { Channel } from '../dsh-adapter/channel.js';
3
3
  import type { WaveBand } from '../dsh-adapter/types.js';
4
- /**
5
- * The footer under the prompt input, in Claude Code's PromptInputFooter
6
- * layout: the segmented context progress bar on its own first line, the
7
- * status line below (left group: model · tokens · think level · cache · tps
8
- * gauge/sparkline; right group: git · cwd · title · short session id,
9
- * right-aligned), and the
10
- * mode/hint line last. The right side of the footer shows the latest
11
- * transient notification (errors in red, warnings in amber — CC style).
12
- */
13
4
  export declare function StatusLine({ channel, selectionActive, helpOpen, wake, }: {
14
5
  channel: Channel;
15
6
  selectionActive?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"StatusLine.d.ts","sourceRoot":"","sources":["../../../src/screens/StatusLine.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAQzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAGxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAQvD;;;;;;;;GAQG;AACH,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,qBA8QA;AAED,KAAK,aAAa,GAAG;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,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;AAQzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAYxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AA6EvD,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,qBA8VA;AAED,KAAK,aAAa,GAAG;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAyHD,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAKvF"}