@deepseek-harness-tui/dsh-tui 0.8.8 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (467) hide show
  1. package/README.md +60 -238
  2. package/bin/dsh-tui.js +172 -5
  3. package/cordis.patch.yml +16 -4
  4. package/dsh-ecosystem-spec/protocols/profile-definitions.d.ts +13 -13
  5. package/dsh-ecosystem-spec/protocols/profile-definitions.js +59 -59
  6. package/dsh-ecosystem-spec/protocols/tui-channel-http.d.ts +15 -15
  7. package/dsh-ecosystem-spec/protocols/tui-channel-http.js +32 -32
  8. package/dsh-ecosystem-spec/protocols/tui-channel.d.ts +59 -59
  9. package/dsh-ecosystem-spec/protocols/tui-channel.js +166 -166
  10. package/dsh-ecosystem-spec/protocols/tui-contributions.d.ts +42 -42
  11. package/dsh-ecosystem-spec/protocols/tui-contributions.js +143 -143
  12. package/dsh-ecosystem-spec/registry/README.md +14 -14
  13. package/dsh-ecosystem-spec/registry/host-descriptor.tui.example.json +56 -56
  14. package/dsh-ecosystem-spec/registry/permissions-0.1.json +13 -13
  15. package/dsh-ecosystem-spec/registry/registry-0.15.json +149 -149
  16. package/lib/types/cc/hyperlink.d.ts +7 -1
  17. package/lib/types/cc/hyperlink.d.ts.map +1 -1
  18. package/lib/types/cc/hyperlink.js +3 -2
  19. package/lib/types/cc/markdown.d.ts.map +1 -1
  20. package/lib/types/cc/markdown.js +33 -3
  21. package/lib/types/cc/sessionColors.d.ts +27 -0
  22. package/lib/types/cc/sessionColors.d.ts.map +1 -0
  23. package/lib/types/cc/sessionColors.js +39 -0
  24. package/lib/types/commands.d.ts.map +1 -1
  25. package/lib/types/commands.js +10 -2
  26. package/lib/types/components/ActivityPicker.d.ts +4 -1
  27. package/lib/types/components/ActivityPicker.d.ts.map +1 -1
  28. package/lib/types/components/ActivityPicker.js +2 -2
  29. package/lib/types/components/AutoRecapRow.d.ts +23 -0
  30. package/lib/types/components/AutoRecapRow.d.ts.map +1 -0
  31. package/lib/types/components/AutoRecapRow.js +23 -0
  32. package/lib/types/components/BtwPanel.d.ts.map +1 -1
  33. package/lib/types/components/BtwPanel.js +1 -1
  34. package/lib/types/components/Chat/SubagentMessage.d.ts +2 -1
  35. package/lib/types/components/Chat/SubagentMessage.d.ts.map +1 -1
  36. package/lib/types/components/Chat/SubagentMessage.js +11 -3
  37. package/lib/types/components/ColorPicker.d.ts +17 -0
  38. package/lib/types/components/ColorPicker.d.ts.map +1 -0
  39. package/lib/types/components/ColorPicker.js +20 -0
  40. package/lib/types/components/CommandSuggestions.d.ts +23 -4
  41. package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
  42. package/lib/types/components/CommandSuggestions.js +41 -14
  43. package/lib/types/components/ContextBarView.d.ts +33 -0
  44. package/lib/types/components/ContextBarView.d.ts.map +1 -0
  45. package/lib/types/components/ContextBarView.js +46 -0
  46. package/lib/types/components/EffortInputBorder.d.ts +12 -1
  47. package/lib/types/components/EffortInputBorder.d.ts.map +1 -1
  48. package/lib/types/components/EffortInputBorder.js +22 -5
  49. package/lib/types/components/EffortSlider.d.ts +4 -1
  50. package/lib/types/components/EffortSlider.d.ts.map +1 -1
  51. package/lib/types/components/EffortSlider.js +4 -2
  52. package/lib/types/components/ExtensionDialog.js +6 -2
  53. package/lib/types/components/FileActionsPanel.d.ts +22 -0
  54. package/lib/types/components/FileActionsPanel.d.ts.map +1 -0
  55. package/lib/types/components/FileActionsPanel.js +28 -0
  56. package/lib/types/components/FileSuggestions.d.ts +26 -7
  57. package/lib/types/components/FileSuggestions.d.ts.map +1 -1
  58. package/lib/types/components/FileSuggestions.js +39 -12
  59. package/lib/types/components/GoalTodoPanel.d.ts +26 -2
  60. package/lib/types/components/GoalTodoPanel.d.ts.map +1 -1
  61. package/lib/types/components/GoalTodoPanel.js +86 -17
  62. package/lib/types/components/HelpMenu.d.ts +7 -1
  63. package/lib/types/components/HelpMenu.d.ts.map +1 -1
  64. package/lib/types/components/HelpMenu.js +12 -4
  65. package/lib/types/components/HistorySearchDialog.d.ts +4 -1
  66. package/lib/types/components/HistorySearchDialog.d.ts.map +1 -1
  67. package/lib/types/components/HistorySearchDialog.js +2 -2
  68. package/lib/types/components/LangPicker.d.ts +14 -0
  69. package/lib/types/components/LangPicker.d.ts.map +1 -0
  70. package/lib/types/components/LangPicker.js +17 -0
  71. package/lib/types/components/LoadedContextPanel.d.ts.map +1 -1
  72. package/lib/types/components/LoadedContextPanel.js +3 -1
  73. package/lib/types/components/Markdown.d.ts.map +1 -1
  74. package/lib/types/components/Markdown.js +12 -3
  75. package/lib/types/components/MessageList.d.ts +45 -2
  76. package/lib/types/components/MessageList.d.ts.map +1 -1
  77. package/lib/types/components/MessageList.js +560 -41
  78. package/lib/types/components/ModelPicker.d.ts +27 -2
  79. package/lib/types/components/ModelPicker.d.ts.map +1 -1
  80. package/lib/types/components/ModelPicker.js +26 -6
  81. package/lib/types/components/PermissionsPicker.d.ts +21 -0
  82. package/lib/types/components/PermissionsPicker.d.ts.map +1 -0
  83. package/lib/types/components/PermissionsPicker.js +27 -0
  84. package/lib/types/components/PlanPicker.d.ts +15 -0
  85. package/lib/types/components/PlanPicker.d.ts.map +1 -0
  86. package/lib/types/components/PlanPicker.js +18 -0
  87. package/lib/types/components/PresetPicker.d.ts +4 -1
  88. package/lib/types/components/PresetPicker.d.ts.map +1 -1
  89. package/lib/types/components/PresetPicker.js +2 -2
  90. package/lib/types/components/PromptInput.d.ts +4 -3
  91. package/lib/types/components/PromptInput.d.ts.map +1 -1
  92. package/lib/types/components/PromptInput.js +602 -75
  93. package/lib/types/components/RecapPanel.d.ts +25 -0
  94. package/lib/types/components/RecapPanel.d.ts.map +1 -0
  95. package/lib/types/components/RecapPanel.js +55 -0
  96. package/lib/types/components/RewindPicker.d.ts +12 -1
  97. package/lib/types/components/RewindPicker.d.ts.map +1 -1
  98. package/lib/types/components/RewindPicker.js +6 -4
  99. package/lib/types/components/ScrollbarGutter.d.ts +28 -0
  100. package/lib/types/components/ScrollbarGutter.d.ts.map +1 -0
  101. package/lib/types/components/ScrollbarGutter.js +119 -0
  102. package/lib/types/components/Select.d.ts +8 -1
  103. package/lib/types/components/Select.d.ts.map +1 -1
  104. package/lib/types/components/Select.js +4 -2
  105. package/lib/types/components/SkillsPicker.d.ts +4 -1
  106. package/lib/types/components/SkillsPicker.d.ts.map +1 -1
  107. package/lib/types/components/SkillsPicker.js +2 -2
  108. package/lib/types/components/SubagentCard.d.ts +2 -1
  109. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  110. package/lib/types/components/SubagentCard.js +9 -2
  111. package/lib/types/components/SubagentDashboard.d.ts +4 -0
  112. package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
  113. package/lib/types/components/SubagentDashboard.js +9 -1
  114. package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
  115. package/lib/types/components/SubagentDetailScene.js +5 -4
  116. package/lib/types/components/SuggestionCard.d.ts +65 -0
  117. package/lib/types/components/SuggestionCard.d.ts.map +1 -0
  118. package/lib/types/components/SuggestionCard.js +77 -0
  119. package/lib/types/components/ThemePicker.d.ts +4 -1
  120. package/lib/types/components/ThemePicker.d.ts.map +1 -1
  121. package/lib/types/components/ThemePicker.js +2 -2
  122. package/lib/types/components/ThinkingToggle.d.ts +4 -1
  123. package/lib/types/components/ThinkingToggle.d.ts.map +1 -1
  124. package/lib/types/components/ThinkingToggle.js +2 -2
  125. package/lib/types/components/TimelineRail.d.ts +53 -0
  126. package/lib/types/components/TimelineRail.d.ts.map +1 -0
  127. package/lib/types/components/TimelineRail.js +197 -0
  128. package/lib/types/components/WorkspaceFlowPicker.d.ts +6 -1
  129. package/lib/types/components/WorkspaceFlowPicker.d.ts.map +1 -1
  130. package/lib/types/components/WorkspaceFlowPicker.js +4 -2
  131. package/lib/types/components/WorkspaceMenuPicker.d.ts +19 -0
  132. package/lib/types/components/WorkspaceMenuPicker.d.ts.map +1 -0
  133. package/lib/types/components/WorkspaceMenuPicker.js +19 -0
  134. package/lib/types/components/WorkspacePicker.d.ts +4 -1
  135. package/lib/types/components/WorkspacePicker.d.ts.map +1 -1
  136. package/lib/types/components/WorkspacePicker.js +2 -2
  137. package/lib/types/components/approvals/ApprovalPanel.d.ts.map +1 -1
  138. package/lib/types/components/approvals/ApprovalPanel.js +5 -1
  139. package/lib/types/components/design-system/ListItem.d.ts +8 -1
  140. package/lib/types/components/design-system/ListItem.d.ts.map +1 -1
  141. package/lib/types/components/design-system/ListItem.js +8 -3
  142. package/lib/types/components/design-system/ThemeProvider.d.ts +7 -0
  143. package/lib/types/components/design-system/ThemeProvider.d.ts.map +1 -1
  144. package/lib/types/components/design-system/ThemeProvider.js +2 -1
  145. package/lib/types/components/messages/AssistantTextMessage.d.ts +5 -2
  146. package/lib/types/components/messages/AssistantTextMessage.d.ts.map +1 -1
  147. package/lib/types/components/messages/AssistantTextMessage.js +6 -2
  148. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +2 -1
  149. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  150. package/lib/types/components/messages/AssistantThinkingMessage.js +10 -4
  151. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +15 -1
  152. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  153. package/lib/types/components/messages/AssistantToolUseMessage.js +37 -7
  154. package/lib/types/components/messages/UserPromptMessage.d.ts +2 -1
  155. package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
  156. package/lib/types/components/questions/AskUserQuestionPanel.d.ts +7 -3
  157. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  158. package/lib/types/components/questions/AskUserQuestionPanel.js +75 -11
  159. package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
  160. package/lib/types/components/questions/PlanReviewPanel.js +13 -2
  161. package/lib/types/components/sessions/SessionListRow.d.ts +4 -1
  162. package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
  163. package/lib/types/components/sessions/SessionListRow.js +4 -2
  164. package/lib/types/components/trajectory/HotspotView.d.ts +7 -1
  165. package/lib/types/components/trajectory/HotspotView.d.ts.map +1 -1
  166. package/lib/types/components/trajectory/HotspotView.js +8 -2
  167. package/lib/types/components/trajectory/Ledger.d.ts +9 -1
  168. package/lib/types/components/trajectory/Ledger.d.ts.map +1 -1
  169. package/lib/types/components/trajectory/Ledger.js +23 -5
  170. package/lib/types/components/trajectory/WaveBand.d.ts +10 -1
  171. package/lib/types/components/trajectory/WaveBand.d.ts.map +1 -1
  172. package/lib/types/components/trajectory/WaveBand.js +7 -2
  173. package/lib/types/dsh-adapter/channel.d.ts +117 -7
  174. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  175. package/lib/types/dsh-adapter/channel.js +1301 -122
  176. package/lib/types/dsh-adapter/compat/index.d.ts +8 -6
  177. package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -1
  178. package/lib/types/dsh-adapter/compat/index.js +8 -6
  179. package/lib/types/dsh-adapter/compat/sessionLog.d.ts +150 -0
  180. package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -1
  181. package/lib/types/dsh-adapter/compat/sessionLog.js +518 -41
  182. package/lib/types/dsh-adapter/contract.d.ts +1 -1
  183. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  184. package/lib/types/dsh-adapter/contract.js +1 -0
  185. package/lib/types/dsh-adapter/extension-events.d.ts +1 -1
  186. package/lib/types/dsh-adapter/extension-events.d.ts.map +1 -1
  187. package/lib/types/dsh-adapter/index.d.ts +20 -2
  188. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  189. package/lib/types/dsh-adapter/index.js +9 -1
  190. package/lib/types/dsh-adapter/plugin.d.ts +0 -9
  191. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  192. package/lib/types/dsh-adapter/plugin.js +453 -14
  193. package/lib/types/dsh-adapter/presets.d.ts +18 -0
  194. package/lib/types/dsh-adapter/presets.d.ts.map +1 -1
  195. package/lib/types/dsh-adapter/presets.js +31 -0
  196. package/lib/types/dsh-adapter/providerWizard.d.ts +29 -1
  197. package/lib/types/dsh-adapter/providerWizard.d.ts.map +1 -1
  198. package/lib/types/dsh-adapter/providerWizard.js +89 -5
  199. package/lib/types/dsh-adapter/questions.d.ts +19 -2
  200. package/lib/types/dsh-adapter/questions.d.ts.map +1 -1
  201. package/lib/types/dsh-adapter/questions.js +53 -10
  202. package/lib/types/dsh-adapter/recap.d.ts +49 -0
  203. package/lib/types/dsh-adapter/recap.d.ts.map +1 -0
  204. package/lib/types/dsh-adapter/recap.js +121 -0
  205. package/lib/types/dsh-adapter/sessionTree.d.ts +314 -0
  206. package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -0
  207. package/lib/types/dsh-adapter/sessionTree.js +954 -0
  208. package/lib/types/dsh-adapter/shortcuts.d.ts +15 -44
  209. package/lib/types/dsh-adapter/shortcuts.d.ts.map +1 -1
  210. package/lib/types/dsh-adapter/shortcuts.js +28 -165
  211. package/lib/types/dsh-adapter/types.d.ts +1 -1
  212. package/lib/types/dsh-adapter/types.d.ts.map +1 -1
  213. package/lib/types/herdr.js +1 -1
  214. package/lib/types/i18n.d.ts +770 -181
  215. package/lib/types/i18n.d.ts.map +1 -1
  216. package/lib/types/i18n.js +257 -80
  217. package/lib/types/ink/components/AlternateScreen.d.ts.map +1 -1
  218. package/lib/types/ink/components/AlternateScreen.js +13 -1
  219. package/lib/types/ink/components/App.d.ts +12 -1
  220. package/lib/types/ink/components/App.d.ts.map +1 -1
  221. package/lib/types/ink/components/App.js +101 -4
  222. package/lib/types/ink/components/ClockContext.d.ts.map +1 -1
  223. package/lib/types/ink/components/ClockContext.js +2 -0
  224. package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
  225. package/lib/types/ink/components/ScrollBox.js +170 -91
  226. package/lib/types/ink/constants.d.ts +9 -0
  227. package/lib/types/ink/constants.d.ts.map +1 -1
  228. package/lib/types/ink/constants.js +9 -0
  229. package/lib/types/ink/events/click-event.d.ts +7 -16
  230. package/lib/types/ink/events/click-event.d.ts.map +1 -1
  231. package/lib/types/ink/events/click-event.js +16 -19
  232. package/lib/types/ink/events/event-handlers.d.ts +11 -1
  233. package/lib/types/ink/events/event-handlers.d.ts.map +1 -1
  234. package/lib/types/ink/events/event-handlers.js +2 -0
  235. package/lib/types/ink/events/input-event.d.ts +9 -0
  236. package/lib/types/ink/events/input-event.d.ts.map +1 -1
  237. package/lib/types/ink/events/input-event.js +4 -0
  238. package/lib/types/ink/events/pointer-event.d.ts +61 -0
  239. package/lib/types/ink/events/pointer-event.d.ts.map +1 -0
  240. package/lib/types/ink/events/pointer-event.js +61 -0
  241. package/lib/types/ink/events/wheel-event.d.ts +17 -0
  242. package/lib/types/ink/events/wheel-event.d.ts.map +1 -0
  243. package/lib/types/ink/events/wheel-event.js +20 -0
  244. package/lib/types/ink/geometry-trace.d.ts +51 -0
  245. package/lib/types/ink/geometry-trace.d.ts.map +1 -0
  246. package/lib/types/ink/geometry-trace.js +83 -0
  247. package/lib/types/ink/hit-test.d.ts +56 -1
  248. package/lib/types/ink/hit-test.d.ts.map +1 -1
  249. package/lib/types/ink/hit-test.js +146 -8
  250. package/lib/types/ink/ink.d.ts +58 -1
  251. package/lib/types/ink/ink.d.ts.map +1 -1
  252. package/lib/types/ink/ink.js +230 -29
  253. package/lib/types/ink/log-update.d.ts.map +1 -1
  254. package/lib/types/ink/log-update.js +21 -0
  255. package/lib/types/ink/node-cache.d.ts +5 -0
  256. package/lib/types/ink/node-cache.d.ts.map +1 -1
  257. package/lib/types/ink/parse-keypress.d.ts +8 -0
  258. package/lib/types/ink/parse-keypress.d.ts.map +1 -1
  259. package/lib/types/ink/parse-keypress.js +101 -12
  260. package/lib/types/ink/render-node-to-output.d.ts +10 -0
  261. package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
  262. package/lib/types/ink/render-node-to-output.js +111 -18
  263. package/lib/types/ink/timeline-rail.d.ts +138 -0
  264. package/lib/types/ink/timeline-rail.d.ts.map +1 -0
  265. package/lib/types/ink/timeline-rail.js +179 -0
  266. package/lib/types/ink/wrap-text.d.ts.map +1 -1
  267. package/lib/types/ink/wrap-text.js +47 -5
  268. package/lib/types/migrationPrefs.d.ts +60 -0
  269. package/lib/types/migrationPrefs.d.ts.map +1 -0
  270. package/lib/types/migrationPrefs.js +97 -0
  271. package/lib/types/modelGroups.d.ts +72 -0
  272. package/lib/types/modelGroups.d.ts.map +1 -0
  273. package/lib/types/modelGroups.js +97 -0
  274. package/lib/types/modelRecents.d.ts +39 -0
  275. package/lib/types/modelRecents.d.ts.map +1 -0
  276. package/lib/types/modelRecents.js +97 -0
  277. package/lib/types/native-ts/yoga-layout/index.d.ts +11 -0
  278. package/lib/types/native-ts/yoga-layout/index.d.ts.map +1 -1
  279. package/lib/types/native-ts/yoga-layout/index.js +31 -1
  280. package/lib/types/oauth.d.ts +15 -0
  281. package/lib/types/oauth.d.ts.map +1 -0
  282. package/lib/types/oauth.js +14 -0
  283. package/lib/types/reload.d.ts +109 -0
  284. package/lib/types/reload.d.ts.map +1 -0
  285. package/lib/types/reload.js +118 -0
  286. package/lib/types/screens/Chat.d.ts +3 -1
  287. package/lib/types/screens/Chat.d.ts.map +1 -1
  288. package/lib/types/screens/Chat.js +1377 -371
  289. package/lib/types/screens/SessionBrowser.d.ts.map +1 -1
  290. package/lib/types/screens/SessionBrowser.js +56 -29
  291. package/lib/types/screens/SessionTree.d.ts +27 -0
  292. package/lib/types/screens/SessionTree.d.ts.map +1 -0
  293. package/lib/types/screens/SessionTree.js +555 -0
  294. package/lib/types/screens/Settings.d.ts.map +1 -1
  295. package/lib/types/screens/Settings.js +64 -22
  296. package/lib/types/screens/StatusLine.d.ts +0 -8
  297. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  298. package/lib/types/screens/StatusLine.js +224 -45
  299. package/lib/types/screens/StatusMetrics.d.ts +35 -3
  300. package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
  301. package/lib/types/screens/StatusMetrics.js +63 -8
  302. package/lib/types/screens/TrajectoryScene.d.ts.map +1 -1
  303. package/lib/types/screens/TrajectoryScene.js +81 -14
  304. package/lib/types/screens/chatOverlay.d.ts +237 -0
  305. package/lib/types/screens/chatOverlay.d.ts.map +1 -0
  306. package/lib/types/screens/chatOverlay.js +116 -0
  307. package/lib/types/tips.d.ts.map +1 -1
  308. package/lib/types/tips.js +64 -10
  309. package/lib/types/tuiDisplayPrefs.d.ts +15 -0
  310. package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
  311. package/lib/types/tuiDisplayPrefs.js +9 -0
  312. package/lib/types/update.d.ts +139 -0
  313. package/lib/types/update.d.ts.map +1 -1
  314. package/lib/types/update.js +382 -30
  315. package/lib/types/utils/debug.d.ts +10 -0
  316. package/lib/types/utils/debug.d.ts.map +1 -1
  317. package/lib/types/utils/debug.js +24 -0
  318. package/lib/types/utils/fileTarget.d.ts +46 -0
  319. package/lib/types/utils/fileTarget.d.ts.map +1 -0
  320. package/lib/types/utils/fileTarget.js +178 -0
  321. package/lib/types/utils/keymap.d.ts +134 -0
  322. package/lib/types/utils/keymap.d.ts.map +1 -0
  323. package/lib/types/utils/keymap.js +311 -0
  324. package/lib/types/utils/mentions.d.ts +25 -2
  325. package/lib/types/utils/mentions.d.ts.map +1 -1
  326. package/lib/types/utils/mentions.js +69 -10
  327. package/lib/types/utils/openExternal.d.ts +50 -0
  328. package/lib/types/utils/openExternal.d.ts.map +1 -0
  329. package/lib/types/utils/openExternal.js +170 -0
  330. package/lib/types/utils/paths.d.ts.map +1 -1
  331. package/lib/types/utils/paths.js +1 -0
  332. package/node_modules/@deepseek-harness-tui/dsh-auth/LICENSE +21 -0
  333. package/node_modules/@deepseek-harness-tui/dsh-auth/README.md +140 -0
  334. package/node_modules/@deepseek-harness-tui/dsh-auth/cordis.patch.yml +11 -0
  335. package/node_modules/@deepseek-harness-tui/dsh-auth/dsh-plugin.json +44 -0
  336. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/command.d.ts +14 -0
  337. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/command.js +67 -0
  338. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/credentials.d.ts +64 -0
  339. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/credentials.js +170 -0
  340. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/index.d.ts +79 -0
  341. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/index.js +196 -0
  342. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/interaction.d.ts +68 -0
  343. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/interaction.js +193 -0
  344. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/opener.d.ts +32 -0
  345. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/opener.js +101 -0
  346. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/profiles.d.ts +31 -0
  347. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/profiles.js +68 -0
  348. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/service.d.ts +69 -0
  349. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/service.js +129 -0
  350. package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +70 -0
  351. package/node_modules/@dsh-std/command/CHANGELOG.md +8 -8
  352. package/node_modules/@dsh-std/command/LICENSE +21 -21
  353. package/node_modules/@dsh-std/command/README.md +26 -26
  354. package/node_modules/@dsh-std/command/README.zh.md +28 -28
  355. package/node_modules/@dsh-std/command/lib/index.js.map +1 -1
  356. package/node_modules/@dsh-std/command/package.json +22 -22
  357. package/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
  358. package/node_modules/@dsh-std/connection/LICENSE +21 -21
  359. package/node_modules/@dsh-std/connection/README.md +42 -42
  360. package/node_modules/@dsh-std/connection/README.zh.md +42 -42
  361. package/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
  362. package/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  363. package/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
  364. package/node_modules/@dsh-std/connection/package.json +20 -20
  365. package/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  366. package/node_modules/@dsh-std/core/LICENSE +21 -21
  367. package/node_modules/@dsh-std/core/README.md +13 -13
  368. package/node_modules/@dsh-std/core/README.zh.md +13 -13
  369. package/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  370. package/node_modules/@dsh-std/core/package.json +21 -21
  371. package/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
  372. package/node_modules/@dsh-std/manifest/LICENSE +21 -21
  373. package/node_modules/@dsh-std/manifest/README.md +5 -5
  374. package/node_modules/@dsh-std/manifest/README.zh.md +5 -5
  375. package/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
  376. package/node_modules/@dsh-std/manifest/package.json +20 -20
  377. package/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
  378. package/node_modules/@dsh-std/messages/CHANGELOG.md +8 -8
  379. package/node_modules/@dsh-std/messages/LICENSE +21 -21
  380. package/node_modules/@dsh-std/messages/README.md +5 -5
  381. package/node_modules/@dsh-std/messages/README.zh.md +7 -7
  382. package/node_modules/@dsh-std/messages/lib/index.js.map +1 -1
  383. package/node_modules/@dsh-std/messages/package.json +20 -20
  384. package/node_modules/@dsh-std/messages/schema/message-observer-envelope-0.15.schema.json +54 -54
  385. package/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
  386. package/node_modules/@dsh-std/presentation/LICENSE +21 -21
  387. package/node_modules/@dsh-std/presentation/README.md +27 -27
  388. package/node_modules/@dsh-std/presentation/README.zh.md +29 -29
  389. package/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
  390. package/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
  391. package/node_modules/@dsh-std/presentation/package.json +25 -25
  392. package/node_modules/@dsh-std/storage/CHANGELOG.md +8 -8
  393. package/node_modules/@dsh-std/storage/LICENSE +21 -21
  394. package/node_modules/@dsh-std/storage/README.md +5 -5
  395. package/node_modules/@dsh-std/storage/README.zh.md +7 -7
  396. package/node_modules/@dsh-std/storage/lib/index.js.map +1 -1
  397. package/node_modules/@dsh-std/storage/package.json +20 -20
  398. package/node_modules/@dsh-std/storage/schema/local-storage-0.15.schema.json +56 -56
  399. package/package.json +19 -5
  400. package/presets/liangshen/.dsh-tui-managed.json +1 -1
  401. package/presets/liangshen/instruction-hint.mjs +8 -0
  402. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
  403. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/LICENSE +21 -21
  404. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.md +42 -42
  405. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.zh.md +42 -42
  406. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
  407. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  408. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
  409. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/package.json +20 -20
  410. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  411. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/LICENSE +21 -21
  412. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.md +13 -13
  413. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.zh.md +13 -13
  414. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  415. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/package.json +21 -21
  416. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
  417. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/LICENSE +21 -21
  418. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.md +5 -5
  419. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.zh.md +5 -5
  420. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
  421. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/package.json +20 -20
  422. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
  423. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
  424. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/LICENSE +21 -21
  425. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.md +27 -27
  426. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.zh.md +29 -29
  427. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
  428. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
  429. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/package.json +25 -25
  430. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  431. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/LICENSE +21 -21
  432. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.md +13 -13
  433. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.zh.md +13 -13
  434. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  435. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/package.json +21 -21
  436. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  437. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/LICENSE +21 -21
  438. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.md +13 -13
  439. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.zh.md +13 -13
  440. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  441. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/package.json +21 -21
  442. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  443. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/LICENSE +21 -21
  444. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.md +13 -13
  445. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.zh.md +13 -13
  446. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  447. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/package.json +21 -21
  448. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
  449. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/LICENSE +21 -21
  450. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.md +42 -42
  451. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.zh.md +42 -42
  452. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
  453. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  454. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
  455. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/package.json +20 -20
  456. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  457. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/LICENSE +21 -21
  458. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.md +13 -13
  459. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.zh.md +13 -13
  460. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  461. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/package.json +21 -21
  462. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  463. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/LICENSE +21 -21
  464. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.md +13 -13
  465. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.zh.md +13 -13
  466. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  467. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/package.json +21 -21
@@ -1,10 +1,11 @@
1
1
  import { spawn } from 'node:child_process';
2
- import { readFileSync, realpathSync, renameSync, writeFileSync } from 'node:fs';
2
+ import { appendFileSync, lstatSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
3
3
  import { homedir } from 'node:os';
4
4
  import { dirname, join, resolve } from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { gte, gt, lt, valid } from 'semver';
7
7
  import { shellQuote } from './utils/shellQuote.js';
8
+ import { DATA_DIR } from './utils/paths.js';
8
9
  // Re-exported for scripts/verify-update.mjs and the bin launcher, which reads
9
10
  // the compiled copy at lib/types/utils/shellQuote.js.
10
11
  export { shellQuote };
@@ -13,6 +14,72 @@ const DEFAULT_REGISTRY = 'https://registry.npmjs.org';
13
14
  const UPDATE_CHECK_TIMEOUT_MS = 4000;
14
15
  /** env marker set on the /update restart; the new process verifies it at boot. */
15
16
  const UPDATED_FROM_ENV = 'DSH_TUI_UPDATED_FROM';
17
+ /**
18
+ * env marker set on the /restart replacement: its boot logs to restart.log
19
+ * (ordinary launches stay silent, so the file is restart-only evidence).
20
+ */
21
+ const RESTART_CHILD_ENV = 'DSH_TUI_RESTART_CHILD';
22
+ /**
23
+ * Field-diagnosis log for the /restart terminal handoff, appended by BOTH
24
+ * processes: the exiting TUI logs the funnel path, the spawned replacement
25
+ * logs its boot progress, and every line carries pid + timestamp — so a
26
+ * handoff that dies at any stage (loader entry, TTY gate, session resume,
27
+ * even after the parent's survival window) leaves breadcrumbs on disk even
28
+ * when nothing reaches the already-confused terminal. Diagnosis only: every
29
+ * write is best effort and must never break the handoff itself.
30
+ */
31
+ const RESTART_LOG = join(DATA_DIR, 'restart.log');
32
+ /** Cap so a long debugging streak cannot grow the log unbounded. */
33
+ const RESTART_LOG_MAX_BYTES = 256 * 1024;
34
+ function writeRestartLine(line) {
35
+ try {
36
+ mkdirSync(DATA_DIR, { recursive: true });
37
+ appendFileSync(RESTART_LOG, `${new Date().toISOString()} pid=${process.pid} ${line}\n`);
38
+ }
39
+ catch {
40
+ // Diagnosis only.
41
+ }
42
+ }
43
+ /**
44
+ * Append a /restart handoff event to ~/.dsh-tui/restart.log.
45
+ * @param event - Short stable event name.
46
+ * @param data - Small JSON-safe detail (never credentials or session text).
47
+ */
48
+ export function logRestartEvent(event, data) {
49
+ writeRestartLine(`${event}${data === undefined ? '' : ` ${JSON.stringify(data)}`}`);
50
+ }
51
+ /** Start a fresh, clearly delimited /restart attempt block in the log. */
52
+ export function beginRestartAttempt(sessionId) {
53
+ try {
54
+ mkdirSync(DATA_DIR, { recursive: true });
55
+ let size = 0;
56
+ try {
57
+ size = statSync(RESTART_LOG).size;
58
+ }
59
+ catch {
60
+ size = 0;
61
+ }
62
+ if (size > RESTART_LOG_MAX_BYTES)
63
+ writeFileSync(RESTART_LOG, '');
64
+ }
65
+ catch {
66
+ // Diagnosis only.
67
+ }
68
+ writeRestartLine(`--- /restart attempt session=${sessionId} ---`);
69
+ }
70
+ /**
71
+ * Write a handoff notice to stderr synchronously: process.exit() right after
72
+ * an async stream write skips the flush, and a vanished diagnosis is
73
+ * indistinguishable from a silent failure.
74
+ */
75
+ export function writeHandoffNotice(text) {
76
+ try {
77
+ writeFileSync(2, text);
78
+ }
79
+ catch {
80
+ process.stderr.write(text);
81
+ }
82
+ }
16
83
  /** Read the version from either the compiled package or the source checkout. */
17
84
  export function installedTuiVersion() {
18
85
  const here = dirname(fileURLToPath(import.meta.url));
@@ -225,6 +292,79 @@ export function tuiUpdatePluginArgs(profile, targetVersion) {
225
292
  export function isTransientUpdateFailure(stderr) {
226
293
  return /ENOENT|EPERM|EBUSY/i.test(stderr) && /_tmp_\d+/i.test(stderr);
227
294
  }
295
+ /**
296
+ * The pnpm Linux flavor of the tmp-rename race (issue #479): the very same
297
+ * `importPackage` staging path, but overlayfs surfaces the second swap of an
298
+ * already-replaced package dir as EEXIST — deterministically, on every run,
299
+ * never transiently. A plain retry of the identical command ALWAYS fails the
300
+ * same way (the leftover `_tmp_<pid>_<threadId>` staging dir keeps colliding),
301
+ * so this signature must route to the recovery path
302
+ * (removeStalePackageInstall + rerun), not to the plain retry.
303
+ */
304
+ export function isEexistTmpRenameFailure(stderr) {
305
+ return /EEXIST/i.test(stderr) && /_tmp_\d+/i.test(stderr);
306
+ }
307
+ /**
308
+ * The dsh profile layout places plugin packages under
309
+ * `$DSH_HOME ?? ~/.dsh` — the same root dsh itself resolves
310
+ * (`dshHomePath is $DSH_HOME ?? ~/.dsh`, and packaged presets resolve
311
+ * identically). /update's recovery path needs this location to clear a
312
+ * half-updated install pnpm can no longer swap in place (issue #479).
313
+ */
314
+ export function profilePackageDir(profile) {
315
+ const dshHome = process.env.DSH_HOME ?? join(homedir(), '.dsh');
316
+ return join(dshHome, 'profiles', profile, 'node_modules', PACKAGE_NAME);
317
+ }
318
+ /**
319
+ * Recovery for the pnpm tmp-rename races (issues #225/#479): remove the
320
+ * profile's installed copy of this package plus the sibling `_tmp_`
321
+ * staging dirs a crashed swap leaves behind, so the next installer run
322
+ * takes the fresh-install path instead of renaming over the collision.
323
+ * Field-verified workaround (issue #479): `rm -rf <pkg dir>` + rerun
324
+ * succeeds where ten plain retries fail.
325
+ *
326
+ * A junction/symlink at the package dir is UNLINKED only — the link is
327
+ * removed, the target tree (a dev checkout it may point at) is never
328
+ * traversed or deleted. Best effort throughout: this runs inside a
329
+ * failure-recovery branch, so an unusable result simply falls through to
330
+ * the rerun and the manual repair hint.
331
+ */
332
+ export function removeStalePackageInstall(profile) {
333
+ const pkgDir = profilePackageDir(profile);
334
+ const scopeDir = dirname(pkgDir);
335
+ const removal = { packageDir: 'absent', tmpDirs: [] };
336
+ try {
337
+ const stats = lstatSync(pkgDir);
338
+ // lstat reports junctions AND symlinks as isSymbolicLink — remove the
339
+ // link itself, never what it points at.
340
+ if (stats.isSymbolicLink() || stats.isDirectory()) {
341
+ rmSync(pkgDir, { recursive: true, force: true });
342
+ removal.packageDir = 'removed';
343
+ }
344
+ }
345
+ catch (error) {
346
+ removal.packageDir = error.code === 'ENOENT' ? 'absent' : 'failed';
347
+ }
348
+ try {
349
+ for (const name of readdirSync(scopeDir)) {
350
+ if (!/^dsh-tui_tmp_\d+_\d+$/.test(name))
351
+ continue;
352
+ const staging = join(scopeDir, name);
353
+ try {
354
+ rmSync(staging, { recursive: true, force: true });
355
+ removal.tmpDirs.push(name);
356
+ }
357
+ catch {
358
+ // Staging leftovers are best effort; the package dir removal is
359
+ // the load-bearing half of the recovery.
360
+ }
361
+ }
362
+ }
363
+ catch {
364
+ // Unreadable scope dir — nothing more to clear.
365
+ }
366
+ return removal;
367
+ }
228
368
  /**
229
369
  * Best-effort migrate the GLOBAL launcher to the delegating shim (0.8.7):
230
370
  * after a successful profile update, copy this package's `bin/dsh-tui.js`
@@ -290,24 +430,17 @@ export function migrateGlobalLauncher() {
290
430
  return false;
291
431
  }
292
432
  /**
293
- * Update the installed dsh-tui package and restart the same launcher while
294
- * preserving the active session. The TUI must already be unmounted before
295
- * this is called so pnpm output cannot corrupt the rendered terminal frame.
433
+ * Install-only half of `/update`: run `dsh plugin add`, refuse boot-deadlock
434
+ * targets, verify the profile actually advanced, and migrate the global
435
+ * launcher. No restart — `updateTuiAndRestart` layers the session-preserving
436
+ * restart on top, and the `dsh-tui update` CLI stops here.
296
437
  *
297
- * When the preflight registry check resolved an exact target, pass that
298
- * version to pnpm instead of resolving `latest` a second time. This avoids a
299
- * stale mirror/dist-tag response between the check and install. If preflight
300
- * failed, retain the `--latest` fallback: a plain `pnpm update` stays inside
301
- * the manifest range and can restart unchanged across minor releases.
302
- *
303
- * @param sessionId - Session to resume in the replacement process.
304
- * @param profile - The dsh profile this TUI was launched with; updating any
305
- * other profile would leave the running install untouched.
306
- * @param targetVersion - Exact version returned by the preflight registry
307
- * check, or undefined when that check failed and pnpm should resolve latest.
308
- * @returns Exit codes for the update run and the replacement process.
438
+ * @param profile - The dsh profile to update.
439
+ * @param targetVersion - Exact version from the preflight registry check, or
440
+ * undefined when that check failed and pnpm should resolve latest.
441
+ * @returns The update exit code plus the before/after versions.
309
442
  */
310
- export async function updateTuiAndRestart(sessionId, profile, targetVersion) {
443
+ export async function updateTui(profile, targetVersion) {
311
444
  // Stamp the pre-update version BEFORE pnpm runs: it reads this package's
312
445
  // manifest from disk, which the update replaces on the fly — a
313
446
  // post-update read already sees the NEW version, and the restarted
@@ -327,8 +460,23 @@ export async function updateTuiAndRestart(sessionId, profile, targetVersion) {
327
460
  updateStderr = '';
328
461
  updateCode = await runProcess(dsh, updateArgs, { shell: true, onStderr: capture });
329
462
  }
463
+ // Deterministic Linux tmp-rename race (issue #479): EEXIST never clears on
464
+ // a plain retry (the staging-dir collision reproduces every run), and a
465
+ // transient retry that failed again means the same leftover state. Both
466
+ // recover by removing the stale install + staging dirs, then rerunning —
467
+ // the field-verified workaround that takes pnpm down its fresh-install
468
+ // path instead of renaming over the collision.
469
+ if (updateCode !== 0 && (isEexistTmpRenameFailure(updateStderr) || isTransientUpdateFailure(updateStderr))) {
470
+ const flavor = isEexistTmpRenameFailure(updateStderr) ? 'EEXIST, issue #479' : 'retry failed, issue #225';
471
+ const removal = removeStalePackageInstall(profile);
472
+ const stagingNote = removal.tmpDirs.length > 0 ? ` + ${removal.tmpDirs.length} staging dir(s)` : '';
473
+ process.stderr.write(`dsh-tui: pnpm tmp-rename race (${flavor}) — cleared the stale install ` +
474
+ `(package dir: ${removal.packageDir}${stagingNote}) and rerunning the update…\n`);
475
+ updateStderr = '';
476
+ updateCode = await runProcess(dsh, updateArgs, { shell: true, onStderr: capture });
477
+ }
330
478
  if (updateCode !== 0)
331
- return { updateCode, restartCode: updateCode };
479
+ return { code: updateCode, updatedFrom };
332
480
  // A --latest fallback (preflight failed) on a stale mirror can still land
333
481
  // on the 0.7.0–0.7.1 hard-inject range — restarting into it under an older
334
482
  // global-launcher patch is the permanent boot deadlock of issues
@@ -341,7 +489,7 @@ export async function updateTuiAndRestart(sessionId, profile, targetVersion) {
341
489
  `(#183/#307) — NOT restarting into it. Repair with:\n` +
342
490
  ` dsh plugin --profile ${profile} add ${PACKAGE_NAME}@latest\n` +
343
491
  `(if the mirror has not synced the latest release yet, retry later)\n`);
344
- return { updateCode: 1, restartCode: 1 };
492
+ return { code: 1, updatedFrom, installed: installedNow };
345
493
  }
346
494
  // Post-update verification (issue #225): pnpm can report success yet leave
347
495
  // the profile half-updated (manifest old / lockfile new). Verify against
@@ -358,7 +506,7 @@ export async function updateTuiAndRestart(sessionId, profile, targetVersion) {
358
506
  process.stderr.write(`dsh-tui: update completed but the profile still runs ${installed ?? 'an unreadable version'} ` +
359
507
  `(expected ${targetVersion}) — the profile is half-updated. Repair manually with:\n` +
360
508
  ` dsh plugin --profile ${profile} add ${PACKAGE_NAME}@${targetVersion}\n`);
361
- return { updateCode: 1, restartCode: 1 };
509
+ return { code: 1, updatedFrom, installed };
362
510
  }
363
511
  }
364
512
  // Launcher migration (0.8.7): the freshly installed profile carries the
@@ -368,15 +516,219 @@ export async function updateTuiAndRestart(sessionId, profile, targetVersion) {
368
516
  if (migrateGlobalLauncher()) {
369
517
  process.stderr.write('dsh-tui: global launcher aligned to the delegating shim (no manual npm i -g needed anymore).\n');
370
518
  }
371
- const restartCode = await runProcess(process.execPath, [...process.execArgv, ...process.argv.slice(1)], {
372
- env: {
373
- ...process.env,
374
- // Dual-write the resume contract (issue #120): the cordis layer of a
375
- // still-old TUI build reads only DSH_CC_RESUME_SESSION.
376
- DSH_TUI_RESUME_SESSION: sessionId,
377
- DSH_CC_RESUME_SESSION: sessionId,
378
- [UPDATED_FROM_ENV]: updatedFrom,
379
- },
519
+ return { code: 0, updatedFrom, installed: installedTuiVersion() };
520
+ }
521
+ /**
522
+ * Update the installed dsh-tui package and restart the same launcher while
523
+ * preserving the active session. The TUI must already be unmounted before
524
+ * this is called so pnpm output cannot corrupt the rendered terminal frame.
525
+ *
526
+ * When the preflight registry check resolved an exact target, pass that
527
+ * version to pnpm instead of resolving `latest` a second time. This avoids a
528
+ * stale mirror/dist-tag response between the check and install. If preflight
529
+ * failed, retain the `--latest` fallback: a plain `pnpm update` stays inside
530
+ * the manifest range and can restart unchanged across minor releases.
531
+ *
532
+ * @param sessionId - Session to resume in the replacement process.
533
+ * @param profile - The dsh profile this TUI was launched with; updating any
534
+ * other profile would leave the running install untouched.
535
+ * @param targetVersion - Exact version returned by the preflight registry
536
+ * check, or undefined when that check failed and pnpm should resolve latest.
537
+ * @returns Exit codes for the update run and the replacement process.
538
+ */
539
+ export async function updateTuiAndRestart(sessionId, profile, targetVersion) {
540
+ const outcome = await updateTui(profile, targetVersion);
541
+ const { updatedFrom } = outcome;
542
+ if (outcome.code !== 0)
543
+ return { updateCode: outcome.code, restartCode: outcome.code };
544
+ // Restart through the same hardened handoff as /restart (issues
545
+ // #284/#307/#483): wait for the replacement's natural exit (the outer
546
+ // interpreter must not reclaim the console under it), re-assert the
547
+ // stdin detach from a watchdog so a revived pump cannot swallow the
548
+ // child's keypresses, and capture a fast-death stderr report. The old
549
+ // plain inherit spawn raced the interpreter for input on Windows
550
+ // Terminal (issue #483: "cannot type anything after /update").
551
+ const restartCode = await restartTui(sessionId, {
552
+ env: { [UPDATED_FROM_ENV]: updatedFrom },
553
+ kind: 'update',
554
+ });
555
+ return { updateCode: 0, restartCode };
556
+ }
557
+ /**
558
+ * Headless `dsh-tui update`: the `/update` decision flow (preflight, deadlock
559
+ * refusal, mirror-lag note, `--latest` fallback) followed by the install-only
560
+ * half — no TUI, no restart. The bin launcher dynamic-imports this from the
561
+ * profile copy's compiled lib.
562
+ *
563
+ * @param profile - The dsh profile to update.
564
+ * @returns Process exit code: 0 on success or already-latest, 1 otherwise.
565
+ */
566
+ export async function cliUpdate(profile) {
567
+ const target = await resolveTuiUpdateTarget();
568
+ if (target.kind === 'latest') {
569
+ process.stdout.write(`dsh-tui: already the latest version (${target.current}).\n`);
570
+ return 0;
571
+ }
572
+ let targetVersion;
573
+ if (target.kind === 'update') {
574
+ // Mirror the /update flow exactly: refuse the 0.7.0–0.7.1 hard-inject
575
+ // range (permanent boot deadlock under older launcher patches, #183/#307)
576
+ // instead of installing it.
577
+ if (isBootDeadlockTarget(target.latest)) {
578
+ process.stderr.write(`dsh-tui: refusing to update onto ${target.latest} — that range can permanently deadlock boot ` +
579
+ `(#183/#307). Latest on the official registry: ${target.authoritative ?? target.latest}. ` +
580
+ `If you use a mirror, retry after it syncs.\n`);
581
+ return 1;
582
+ }
583
+ if (target.authoritative !== undefined) {
584
+ process.stdout.write(`dsh-tui: note — your registry serves ${target.latest} while npmjs.org has ${target.authoritative} (mirror lag).\n`);
585
+ }
586
+ targetVersion = target.latest;
587
+ process.stdout.write(`dsh-tui: updating ${target.current} → ${target.latest}…\n`);
588
+ }
589
+ else {
590
+ process.stdout.write('dsh-tui: version check failed (offline or unreadable install) — falling back to `--latest`.\n');
591
+ }
592
+ const outcome = await updateTui(profile, targetVersion);
593
+ if (outcome.code === 0) {
594
+ // A preflight-less run (`--latest` fallback) can "succeed" as a pnpm
595
+ // no-op: same manifest before and after. Say so instead of printing a
596
+ // vacuous `updated X → X` — the /update path surfaces the same state via
597
+ // the DSH_TUI_UPDATED_FROM stamp on restart.
598
+ if (targetVersion === undefined && outcome.installed !== undefined && outcome.installed === outcome.updatedFrom) {
599
+ process.stdout.write(`dsh-tui: version did not advance (still ${outcome.installed}) — already the latest, or the registry has no newer release yet.\n`);
600
+ }
601
+ else {
602
+ process.stdout.write(`dsh-tui: updated ${outcome.updatedFrom || '(unknown)'} → ${outcome.installed ?? '(unreadable)'}.\n`);
603
+ }
604
+ }
605
+ return outcome.code;
606
+ }
607
+ export async function restartTui(sessionId, options = {}) {
608
+ const kind = options.kind ?? 'restart';
609
+ const tag = kind === 'update' ? 'update-restart' : 'restart';
610
+ const argv = [...process.execArgv, ...process.argv.slice(1)];
611
+ logRestartEvent(`${tag}: spawning replacement`, {
612
+ node: process.execPath,
613
+ argv,
614
+ cwd: process.cwd(),
615
+ stdinTty: process.stdin.isTTY === true,
616
+ stdoutTty: process.stdout.isTTY === true,
617
+ stderrTty: process.stderr.isTTY === true,
618
+ nodeOptions: process.env.NODE_OPTIONS ?? null,
619
+ dshHome: process.env.DSH_HOME ?? null,
620
+ });
621
+ const startedAt = Date.now();
622
+ return new Promise(resolve => {
623
+ const child = spawn(process.execPath, argv, {
624
+ env: {
625
+ ...process.env,
626
+ // Dual-write the resume contract (issue #120): the cordis layer of a
627
+ // still-old TUI build reads only DSH_CC_RESUME_SESSION.
628
+ DSH_TUI_RESUME_SESSION: sessionId,
629
+ DSH_CC_RESUME_SESSION: sessionId,
630
+ // Marks the replacement so its own boot logs to restart.log without
631
+ // noisy logging on every ordinary launch (/restart only).
632
+ ...(kind === 'restart' ? { [RESTART_CHILD_ENV]: '1' } : {}),
633
+ ...options.env,
634
+ },
635
+ // stdin/stdout stay inherited so the replacement owns the console the
636
+ // moment it boots; stderr is captured so a boot failure is reportable
637
+ // through THIS process (the terminal may already be mid-handoff when
638
+ // the child dies, and a raw inherit write can vanish).
639
+ stdio: ['inherit', 'inherit', 'pipe'],
640
+ });
641
+ logRestartEvent(`${tag}: replacement spawned`, { childPid: child.pid });
642
+ // Handoff watchdog (field evidence 2026-08-24: restarted TUI mounts but
643
+ // takes no input). Two jobs, both diagnosis-grade:
644
+ // 1. SAMPLE this process's stdin state every second — if anything
645
+ // re-attaches a reader after the funnel's detachStdinForHandoff, the
646
+ // sample (taken before the re-assert below) shows it in the log.
647
+ // 2. RE-ASSERT the detach and finally destroy the stream: this process
648
+ // must never read the shared console again — every keypress belongs
649
+ // to the replacement, and a resumed pump here is exactly the
650
+ // "restarted TUI sees dropped or swallowed input" failure (#284/#307).
651
+ let watchdogTicks = 0;
652
+ const watchdog = setInterval(() => {
653
+ watchdogTicks += 1;
654
+ const stdin = process.stdin;
655
+ logRestartEvent('parent: stdin watchdog', {
656
+ tick: watchdogTicks,
657
+ readableListeners: stdin.listenerCount('readable'),
658
+ dataListeners: stdin.listenerCount('data'),
659
+ paused: stdin.isPaused,
660
+ raw: stdin.isRaw === true,
661
+ buffered: stdin.readableLength,
662
+ });
663
+ try {
664
+ stdin.removeAllListeners('readable');
665
+ stdin.removeAllListeners('data');
666
+ stdin.pause();
667
+ }
668
+ catch {
669
+ // Diagnosis/mitigation only.
670
+ }
671
+ if (watchdogTicks === 15) {
672
+ clearInterval(watchdog);
673
+ try {
674
+ // Terminal safeguard: a destroyed stream can never be resumed by
675
+ // any late re-attachment. The child holds its own inherited
676
+ // handle, so closing ours does not affect it.
677
+ process.stdin.destroy();
678
+ logRestartEvent('parent: stdin destroyed after watchdog');
679
+ }
680
+ catch {
681
+ // Best effort.
682
+ }
683
+ }
684
+ }, 1000);
685
+ watchdog.unref();
686
+ let childStderr = '';
687
+ let loggedStderrBytes = 0;
688
+ child.stderr?.on('data', (chunk) => {
689
+ childStderr += chunk.toString('utf8');
690
+ // Mirror chunks to the log capped: the full text still reaches the
691
+ // terminal report below, and unbounded output must not grow the file.
692
+ if (loggedStderrBytes < 4096) {
693
+ loggedStderrBytes += chunk.length;
694
+ logRestartEvent(`${tag}: replacement stderr`, { text: chunk.toString('utf8').slice(0, 2048) });
695
+ }
696
+ });
697
+ // Diagnosis marker only — never resolves: after the window the child owns
698
+ // the terminal, and this process must keep the launch chain open until
699
+ // the replacement exits (see the header comment).
700
+ const timer = setTimeout(() => {
701
+ logRestartEvent(`${tag}: survival window passed, following the replacement until it exits`);
702
+ }, 4000);
703
+ timer.unref();
704
+ child.once('error', error => {
705
+ clearTimeout(timer);
706
+ logRestartEvent(`${tag}: spawn error`, { message: error.message });
707
+ writeHandoffNotice(`dsh-tui: failed to spawn the restart: ${error.message}\n`);
708
+ resolve(127);
709
+ });
710
+ child.once('close', (code, signal) => {
711
+ clearTimeout(timer);
712
+ const elapsedMs = Date.now() - startedAt;
713
+ logRestartEvent(`${tag}: replacement exited`, {
714
+ code: code ?? null,
715
+ signal: signal ?? null,
716
+ elapsedMs,
717
+ });
718
+ if (elapsedMs < 4000) {
719
+ // Fast death: the TUI never came up. Synchronous stderr write —
720
+ // process.exit() right after an async stream write skips the flush,
721
+ // and a vanished diagnosis is indistinguishable from silent failure.
722
+ const suffix = childStderr.trim() === '' ? '' : `\n${childStderr.trimEnd()}`;
723
+ writeHandoffNotice(`dsh-tui: restart child exited during the handoff (code ${code ?? 'null'}` +
724
+ `${signal === undefined || signal === null ? '' : `, signal ${signal}`}) — the TUI did not come up.` +
725
+ `${suffix}\nYour session is preserved; resume with the launcher or retry the command.\n`);
726
+ }
727
+ else if (code !== 0 && code !== null) {
728
+ // Late nonzero exit: the session ended abnormally, say so briefly.
729
+ writeHandoffNotice(`\ndsh-tui: the restarted session exited with code ${code}.\n`);
730
+ }
731
+ resolve(code ?? 1);
732
+ });
380
733
  });
381
- return { updateCode, restartCode };
382
734
  }
@@ -5,4 +5,14 @@
5
5
  * @param fields - Optional JSON-serialized fields appended to the line.
6
6
  */
7
7
  export declare function logForDebugging(message: string, fields?: Record<string, unknown>): void;
8
+ /**
9
+ * Mouse-chain diagnostics: appends to `~/.dsh-tui/mouse-debug.log` when
10
+ * `DSH_TUI_DEBUG_MOUSE` is set. Unlike logForDebugging (stderr), a file
11
+ * keeps the fullscreen alt screen unpolluted and survives the session for
12
+ * post-mortem reading. Every append is try/catch-guarded — diagnostics
13
+ * must never take the UI down.
14
+ * @param message - Stage name (e.g. 'mouse arrive', 'dispatchClick').
15
+ * @param fields - Optional JSON-serialized fields appended to the line.
16
+ */
17
+ export declare function logMouseDebug(message: string, fields?: Record<string, unknown>): void;
8
18
  //# sourceMappingURL=debug.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../../src/utils/debug.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAIvF"}
1
+ {"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../../src/utils/debug.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAIvF;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CASrF"}
@@ -1,3 +1,6 @@
1
+ import { appendFileSync } from 'node:fs';
2
+ import { DATA_DIR } from './paths.js';
3
+ import { join } from 'node:path';
1
4
  /**
2
5
  * Debug logger for the ported Ink core. Writes to stderr only when
3
6
  * `DSH_TUI_DEBUG` is set, so normal runs stay quiet.
@@ -10,3 +13,24 @@ export function logForDebugging(message, fields) {
10
13
  const suffix = fields === undefined ? '' : ` ${JSON.stringify(fields)}`;
11
14
  process.stderr.write(`[dsh-tui] ${message}${suffix}\n`);
12
15
  }
16
+ /**
17
+ * Mouse-chain diagnostics: appends to `~/.dsh-tui/mouse-debug.log` when
18
+ * `DSH_TUI_DEBUG_MOUSE` is set. Unlike logForDebugging (stderr), a file
19
+ * keeps the fullscreen alt screen unpolluted and survives the session for
20
+ * post-mortem reading. Every append is try/catch-guarded — diagnostics
21
+ * must never take the UI down.
22
+ * @param message - Stage name (e.g. 'mouse arrive', 'dispatchClick').
23
+ * @param fields - Optional JSON-serialized fields appended to the line.
24
+ */
25
+ export function logMouseDebug(message, fields) {
26
+ if (!process.env.DSH_TUI_DEBUG_MOUSE)
27
+ return;
28
+ const suffix = fields === undefined ? '' : ` ${JSON.stringify(fields)}`;
29
+ try {
30
+ const line = `${new Date().toISOString()} ${message}${suffix}\n`;
31
+ appendFileSync(join(DATA_DIR, 'mouse-debug.log'), line);
32
+ }
33
+ catch {
34
+ // ignore — see doc comment
35
+ }
36
+ }
@@ -0,0 +1,46 @@
1
+ /** Our custom OSC 8 scheme carrying a raw display path (URI-encoded). */
2
+ export declare const FILE_LINK_SCHEME = "dsh-file:";
3
+ /** Encode a display path into a `dsh-file:` link URL. */
4
+ export declare function fileLinkUrl(path: string): string;
5
+ /**
6
+ * Decode a `dsh-file:` link URL back to the raw display path. Returns
7
+ * undefined for anything that is not a well-formed dsh-file URL.
8
+ */
9
+ export declare function parseFileLinkUrl(url: string): string | undefined;
10
+ /**
11
+ * Resolve a target (raw display path) against the session's base directory:
12
+ * absolute paths and `~` pass through (with ~ expanded), everything else is
13
+ * joined onto the base. Pure, so it is unit-testable without a workspace.
14
+ */
15
+ export declare function resolveTargetPath(path: string, baseDir: string): string;
16
+ /**
17
+ * Convert a `file://` URL to a local path. Wraps node:url.fileURLToPath —
18
+ * undefined when the URL is not a valid file URL.
19
+ */
20
+ export declare function fileUrlToPath(url: string): string | undefined;
21
+ /**
22
+ * Conservative heuristic: does this text look like a file path worth
23
+ * making clickable? Requires a slash separator, no whitespace, no URL/email
24
+ * shape, and either a path anchor (`./`, `../`, `/`, `~/`, drive letter)
25
+ * with a real path shape (another separator or an extension — a bare
26
+ * anchored word like `/a` or `x.com/a` is too ambiguous), or a plausible
27
+ * file extension. Length-capped so huge tokens (base64, logs) never get
28
+ * linked.
29
+ */
30
+ export declare function looksLikeFilePath(text: string): boolean;
31
+ /**
32
+ * Best-effort existence hint: does `path` exist on disk? Used to decide
33
+ * whether to render a path as clickable in contexts where the raw text is
34
+ * ambiguous; never throws.
35
+ */
36
+ export declare function pathExistsOnDisk(path: string): boolean;
37
+ /**
38
+ * Replace every path-looking span in `text` via `wrap(path, display)`.
39
+ * Trailing sentence punctuation stays OUTSIDE the wrapped display (so
40
+ * "src/foo.ts." links `src/foo.ts` and keeps the period). Spans that fail
41
+ * `looksLikeFilePath` are returned unchanged.
42
+ * @param text - plain text to scan (no ANSI).
43
+ * @param wrap - builds the clickable rendering for one path.
44
+ */
45
+ export declare function linkifyFilePaths(text: string, wrap: (path: string, display: string) => string): string;
46
+ //# sourceMappingURL=fileTarget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileTarget.d.ts","sourceRoot":"","sources":["../../../src/utils/fileTarget.ts"],"names":[],"mappings":"AAuBA,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,cAAc,CAAA;AAE3C,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOhE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAWvE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAM7D;AA0BD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAoBvD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMtD;AAWD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,GAC9C,MAAM,CAcR"}