@deepseek-harness-tui/dsh-tui 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (379) hide show
  1. package/README.md +74 -21
  2. package/bin/dsh-tui.js +115 -25
  3. package/cordis.patch.yml +69 -17
  4. package/cordis.yml +50 -12
  5. package/lib/types/activityPrefs.d.ts +1 -1
  6. package/lib/types/activityPrefs.js +3 -3
  7. package/lib/types/cc/figures.d.ts +27 -20
  8. package/lib/types/cc/figures.d.ts.map +1 -1
  9. package/lib/types/cc/figures.js +43 -34
  10. package/lib/types/cc/format.d.ts +18 -9
  11. package/lib/types/cc/format.d.ts.map +1 -1
  12. package/lib/types/cc/format.js +26 -18
  13. package/lib/types/cc/markdown.d.ts +31 -16
  14. package/lib/types/cc/markdown.d.ts.map +1 -1
  15. package/lib/types/cc/markdown.js +283 -260
  16. package/lib/types/cc/terminal.d.ts +10 -7
  17. package/lib/types/cc/terminal.d.ts.map +1 -1
  18. package/lib/types/cc/terminal.js +62 -50
  19. package/lib/types/command-trees.d.ts +3 -0
  20. package/lib/types/command-trees.d.ts.map +1 -0
  21. package/lib/types/command-trees.js +4 -0
  22. package/lib/types/commands.d.ts +37 -1
  23. package/lib/types/commands.d.ts.map +1 -1
  24. package/lib/types/commands.js +68 -3
  25. package/lib/types/components/ActivityLine.d.ts +1 -1
  26. package/lib/types/components/ActivityLine.d.ts.map +1 -1
  27. package/lib/types/components/ActivityPicker.d.ts.map +1 -1
  28. package/lib/types/components/ActivityPicker.js +3 -4
  29. package/lib/types/components/BtwPanel.d.ts +16 -0
  30. package/lib/types/components/BtwPanel.d.ts.map +1 -0
  31. package/lib/types/components/BtwPanel.js +47 -0
  32. package/lib/types/components/CommandSuggestions.d.ts +4 -2
  33. package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
  34. package/lib/types/components/CommandSuggestions.js +2 -2
  35. package/lib/types/components/EffortSlider.d.ts +15 -0
  36. package/lib/types/components/EffortSlider.d.ts.map +1 -0
  37. package/lib/types/components/EffortSlider.js +17 -0
  38. package/lib/types/components/GoalTodoPanel.d.ts +1 -1
  39. package/lib/types/components/GoalTodoPanel.d.ts.map +1 -1
  40. package/lib/types/components/HelpMenu.d.ts +5 -2
  41. package/lib/types/components/HelpMenu.d.ts.map +1 -1
  42. package/lib/types/components/HelpMenu.js +8 -3
  43. package/lib/types/components/HistorySearchDialog.d.ts +1 -1
  44. package/lib/types/components/HistorySearchDialog.d.ts.map +1 -1
  45. package/lib/types/components/HistorySearchDialog.js +21 -10
  46. package/lib/types/components/InterruptedByUser.d.ts +2 -2
  47. package/lib/types/components/InterruptedByUser.d.ts.map +1 -1
  48. package/lib/types/components/InterruptedByUser.js +4 -3
  49. package/lib/types/components/LoadedContextPanel.d.ts +1 -1
  50. package/lib/types/components/LoadedContextPanel.d.ts.map +1 -1
  51. package/lib/types/components/LogoV2.d.ts.map +1 -1
  52. package/lib/types/components/LogoV2.js +2 -1
  53. package/lib/types/components/Markdown.d.ts +11 -11
  54. package/lib/types/components/Markdown.d.ts.map +1 -1
  55. package/lib/types/components/Markdown.js +63 -57
  56. package/lib/types/components/MarkdownTable.d.ts +1 -1
  57. package/lib/types/components/MarkdownTable.js +2 -2
  58. package/lib/types/components/MessageList.d.ts +10 -2
  59. package/lib/types/components/MessageList.d.ts.map +1 -1
  60. package/lib/types/components/MessageList.js +17 -10
  61. package/lib/types/components/ModelPicker.d.ts +4 -1
  62. package/lib/types/components/ModelPicker.d.ts.map +1 -1
  63. package/lib/types/components/ModelPicker.js +16 -4
  64. package/lib/types/components/OverlayAbove.d.ts +20 -0
  65. package/lib/types/components/OverlayAbove.d.ts.map +1 -0
  66. package/lib/types/components/OverlayAbove.js +18 -0
  67. package/lib/types/components/PresetPicker.d.ts +1 -1
  68. package/lib/types/components/PresetPicker.d.ts.map +1 -1
  69. package/lib/types/components/PresetPicker.js +2 -3
  70. package/lib/types/components/PromptInput.d.ts +5 -4
  71. package/lib/types/components/PromptInput.d.ts.map +1 -1
  72. package/lib/types/components/PromptInput.js +186 -39
  73. package/lib/types/components/ResumePicker.d.ts +15 -4
  74. package/lib/types/components/ResumePicker.d.ts.map +1 -1
  75. package/lib/types/components/ResumePicker.js +25 -9
  76. package/lib/types/components/RewindPicker.d.ts +1 -1
  77. package/lib/types/components/RewindPicker.d.ts.map +1 -1
  78. package/lib/types/components/RewindPicker.js +14 -5
  79. package/lib/types/components/SearchBox.d.ts +1 -1
  80. package/lib/types/components/SearchBox.js +1 -1
  81. package/lib/types/components/Spinner/GlimmerMessage.d.ts +1 -2
  82. package/lib/types/components/Spinner/GlimmerMessage.d.ts.map +1 -1
  83. package/lib/types/components/Spinner/GlimmerMessage.js +1 -2
  84. package/lib/types/components/Spinner/SpinnerAnimationRow.d.ts +1 -1
  85. package/lib/types/components/Spinner/SpinnerAnimationRow.js +2 -2
  86. package/lib/types/components/Spinner/SpinnerGlyph.d.ts +1 -1
  87. package/lib/types/components/Spinner/SpinnerGlyph.js +1 -1
  88. package/lib/types/components/Spinner/spinnerUtils.d.ts +13 -18
  89. package/lib/types/components/Spinner/spinnerUtils.d.ts.map +1 -1
  90. package/lib/types/components/Spinner/spinnerUtils.js +67 -71
  91. package/lib/types/components/Spinner/useStalledAnimation.d.ts +1 -2
  92. package/lib/types/components/Spinner/useStalledAnimation.d.ts.map +1 -1
  93. package/lib/types/components/Spinner/useStalledAnimation.js +1 -2
  94. package/lib/types/components/StreamingMarkdown.d.ts +1 -1
  95. package/lib/types/components/StreamingMarkdown.js +1 -1
  96. package/lib/types/components/ThemePicker.d.ts +13 -9
  97. package/lib/types/components/ThemePicker.d.ts.map +1 -1
  98. package/lib/types/components/ThemePicker.js +21 -15
  99. package/lib/types/components/ThinkingToggle.d.ts +1 -1
  100. package/lib/types/components/ThinkingToggle.d.ts.map +1 -1
  101. package/lib/types/components/ThinkingToggle.js +8 -8
  102. package/lib/types/components/ToolUseLoader.d.ts +1 -1
  103. package/lib/types/components/ToolUseLoader.js +1 -1
  104. package/lib/types/components/WorkingSpinner.d.ts +2 -2
  105. package/lib/types/components/WorkingSpinner.js +2 -2
  106. package/lib/types/components/WorkspaceFlowPicker.d.ts +15 -0
  107. package/lib/types/components/WorkspaceFlowPicker.d.ts.map +1 -0
  108. package/lib/types/components/WorkspaceFlowPicker.js +19 -0
  109. package/lib/types/components/WorkspacePicker.d.ts +9 -0
  110. package/lib/types/components/WorkspacePicker.d.ts.map +1 -0
  111. package/lib/types/components/WorkspacePicker.js +13 -0
  112. package/lib/types/components/approvals/ApprovalPanel.d.ts +1 -1
  113. package/lib/types/components/approvals/ApprovalPanel.d.ts.map +1 -1
  114. package/lib/types/components/approvals/ApprovalPanel.js +2 -1
  115. package/lib/types/components/design-system/Byline.d.ts +1 -1
  116. package/lib/types/components/design-system/Byline.js +1 -1
  117. package/lib/types/components/design-system/Divider.d.ts +1 -1
  118. package/lib/types/components/design-system/Divider.js +1 -1
  119. package/lib/types/components/design-system/HintLine.d.ts +12 -0
  120. package/lib/types/components/design-system/HintLine.d.ts.map +1 -0
  121. package/lib/types/components/design-system/HintLine.js +15 -0
  122. package/lib/types/components/design-system/KeyboardShortcutHint.d.ts +1 -1
  123. package/lib/types/components/design-system/KeyboardShortcutHint.js +1 -1
  124. package/lib/types/components/design-system/ListItem.d.ts +2 -2
  125. package/lib/types/components/design-system/ListItem.d.ts.map +1 -1
  126. package/lib/types/components/design-system/ListItem.js +35 -3
  127. package/lib/types/components/design-system/LoadingState.d.ts +1 -2
  128. package/lib/types/components/design-system/LoadingState.d.ts.map +1 -1
  129. package/lib/types/components/design-system/LoadingState.js +1 -2
  130. package/lib/types/components/design-system/Pane.d.ts +2 -2
  131. package/lib/types/components/design-system/Pane.js +2 -2
  132. package/lib/types/components/design-system/ProgressBar.d.ts +1 -2
  133. package/lib/types/components/design-system/ProgressBar.d.ts.map +1 -1
  134. package/lib/types/components/design-system/ProgressBar.js +1 -2
  135. package/lib/types/components/design-system/StatusIcon.d.ts +2 -2
  136. package/lib/types/components/design-system/StatusIcon.js +2 -2
  137. package/lib/types/components/design-system/ThemeProvider.d.ts +1 -1
  138. package/lib/types/components/design-system/ThemeProvider.d.ts.map +1 -1
  139. package/lib/types/components/design-system/ThemeProvider.js +87 -26
  140. package/lib/types/components/design-system/ThemedBox.d.ts +1 -1
  141. package/lib/types/components/design-system/ThemedBox.js +1 -1
  142. package/lib/types/components/design-system/ThemedText.d.ts +2 -2
  143. package/lib/types/components/design-system/ThemedText.js +2 -2
  144. package/lib/types/components/listWindow.d.ts +26 -0
  145. package/lib/types/components/listWindow.d.ts.map +1 -0
  146. package/lib/types/components/listWindow.js +47 -0
  147. package/lib/types/components/messages/AssistantTextMessage.d.ts +1 -2
  148. package/lib/types/components/messages/AssistantTextMessage.d.ts.map +1 -1
  149. package/lib/types/components/messages/AssistantTextMessage.js +1 -2
  150. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +2 -2
  151. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  152. package/lib/types/components/messages/AssistantThinkingMessage.js +6 -6
  153. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +12 -4
  154. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  155. package/lib/types/components/messages/AssistantToolUseMessage.js +9 -5
  156. package/lib/types/components/messages/MessageMetadata.d.ts +1 -1
  157. package/lib/types/components/messages/MessageMetadata.js +1 -1
  158. package/lib/types/components/messages/UserPromptMessage.d.ts +1 -1
  159. package/lib/types/components/messages/UserPromptMessage.js +1 -1
  160. package/lib/types/components/questions/AskUserQuestionPanel.d.ts +5 -1
  161. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  162. package/lib/types/components/questions/AskUserQuestionPanel.js +11 -9
  163. package/lib/types/components/questions/PlanReviewPanel.d.ts +1 -1
  164. package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
  165. package/lib/types/components/questions/PlanReviewPanel.js +3 -2
  166. package/lib/types/components/trajectory/HotspotView.d.ts +14 -0
  167. package/lib/types/components/trajectory/HotspotView.d.ts.map +1 -0
  168. package/lib/types/components/trajectory/HotspotView.js +83 -0
  169. package/lib/types/components/trajectory/Inspector.d.ts +31 -0
  170. package/lib/types/components/trajectory/Inspector.d.ts.map +1 -0
  171. package/lib/types/components/trajectory/Inspector.js +67 -0
  172. package/lib/types/components/trajectory/Ledger.d.ts +20 -0
  173. package/lib/types/components/trajectory/Ledger.d.ts.map +1 -0
  174. package/lib/types/components/trajectory/Ledger.js +112 -0
  175. package/lib/types/components/trajectory/MiniWake.d.ts +24 -0
  176. package/lib/types/components/trajectory/MiniWake.d.ts.map +1 -0
  177. package/lib/types/components/trajectory/MiniWake.js +99 -0
  178. package/lib/types/components/trajectory/WaveBand.d.ts +33 -0
  179. package/lib/types/components/trajectory/WaveBand.d.ts.map +1 -0
  180. package/lib/types/components/trajectory/WaveBand.js +145 -0
  181. package/lib/types/customTheme.d.ts +6 -6
  182. package/lib/types/customTheme.d.ts.map +1 -1
  183. package/lib/types/customTheme.js +15 -12
  184. package/lib/types/dsh-adapter/approvals.d.ts.map +1 -0
  185. package/lib/types/{channel.d.ts → dsh-adapter/channel.d.ts} +184 -43
  186. package/lib/types/dsh-adapter/channel.d.ts.map +1 -0
  187. package/lib/types/{channel.js → dsh-adapter/channel.js} +972 -201
  188. package/lib/types/dsh-adapter/childStderr.d.ts.map +1 -0
  189. package/lib/types/{childStderr.js → dsh-adapter/childStderr.js} +1 -1
  190. package/lib/types/dsh-adapter/command-trees.d.ts +27 -0
  191. package/lib/types/dsh-adapter/command-trees.d.ts.map +1 -0
  192. package/lib/types/dsh-adapter/command-trees.js +42 -0
  193. package/lib/types/dsh-adapter/compat/index.d.ts +22 -0
  194. package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -0
  195. package/lib/types/{compat → dsh-adapter/compat}/index.js +7 -4
  196. package/lib/types/dsh-adapter/compat/sessionLog.d.ts +86 -0
  197. package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -0
  198. package/lib/types/dsh-adapter/compat/sessionLog.js +347 -0
  199. package/lib/types/dsh-adapter/contract.d.ts +20 -0
  200. package/lib/types/dsh-adapter/contract.d.ts.map +1 -0
  201. package/lib/types/dsh-adapter/contract.js +109 -0
  202. package/lib/types/dsh-adapter/index.d.ts +80 -0
  203. package/lib/types/dsh-adapter/index.d.ts.map +1 -0
  204. package/lib/types/dsh-adapter/index.js +45 -0
  205. package/lib/types/dsh-adapter/invariant.d.ts.map +1 -0
  206. package/lib/types/dsh-adapter/packaged-skills.d.ts.map +1 -0
  207. package/lib/types/{plugin.d.ts → dsh-adapter/plugin.d.ts} +17 -0
  208. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -0
  209. package/lib/types/{plugin.js → dsh-adapter/plugin.js} +280 -80
  210. package/lib/types/dsh-adapter/presets.d.ts.map +1 -0
  211. package/lib/types/dsh-adapter/providerWizard.d.ts +91 -0
  212. package/lib/types/dsh-adapter/providerWizard.d.ts.map +1 -0
  213. package/lib/types/dsh-adapter/providerWizard.js +332 -0
  214. package/lib/types/{questions.d.ts → dsh-adapter/questions.d.ts} +7 -2
  215. package/lib/types/dsh-adapter/questions.d.ts.map +1 -0
  216. package/lib/types/{questions.js → dsh-adapter/questions.js} +15 -7
  217. package/lib/types/dsh-adapter/sideQuestion.d.ts +38 -0
  218. package/lib/types/dsh-adapter/sideQuestion.d.ts.map +1 -0
  219. package/lib/types/dsh-adapter/sideQuestion.js +69 -0
  220. package/lib/types/dsh-adapter/trajectory/aggregate.d.ts +46 -0
  221. package/lib/types/dsh-adapter/trajectory/aggregate.d.ts.map +1 -0
  222. package/lib/types/dsh-adapter/trajectory/aggregate.js +207 -0
  223. package/lib/types/dsh-adapter/trajectory/guards.d.ts +177 -0
  224. package/lib/types/dsh-adapter/trajectory/guards.d.ts.map +1 -0
  225. package/lib/types/dsh-adapter/trajectory/guards.js +235 -0
  226. package/lib/types/dsh-adapter/trajectory/index.d.ts +16 -0
  227. package/lib/types/dsh-adapter/trajectory/index.d.ts.map +1 -0
  228. package/lib/types/dsh-adapter/trajectory/index.js +15 -0
  229. package/lib/types/dsh-adapter/trajectory/inspect.d.ts +40 -0
  230. package/lib/types/dsh-adapter/trajectory/inspect.d.ts.map +1 -0
  231. package/lib/types/dsh-adapter/trajectory/inspect.js +160 -0
  232. package/lib/types/dsh-adapter/trajectory/projection.d.ts +128 -0
  233. package/lib/types/dsh-adapter/trajectory/projection.d.ts.map +1 -0
  234. package/lib/types/dsh-adapter/trajectory/projection.js +653 -0
  235. package/lib/types/dsh-adapter/trajectory/types.d.ts +232 -0
  236. package/lib/types/dsh-adapter/trajectory/types.d.ts.map +1 -0
  237. package/lib/types/dsh-adapter/trajectory/types.js +70 -0
  238. package/lib/types/dsh-adapter/trajectory/wave.d.ts +45 -0
  239. package/lib/types/dsh-adapter/trajectory/wave.d.ts.map +1 -0
  240. package/lib/types/dsh-adapter/trajectory/wave.js +210 -0
  241. package/lib/types/dsh-adapter/types.d.ts +23 -0
  242. package/lib/types/dsh-adapter/types.d.ts.map +1 -0
  243. package/lib/types/dsh-adapter/types.js +1 -0
  244. package/lib/types/dsh-adapter/workspace.d.ts +22 -0
  245. package/lib/types/dsh-adapter/workspace.d.ts.map +1 -0
  246. package/lib/types/dsh-adapter/workspace.js +16 -0
  247. package/lib/types/dsh-adapter/workspaces.d.ts +118 -0
  248. package/lib/types/dsh-adapter/workspaces.d.ts.map +1 -0
  249. package/lib/types/dsh-adapter/workspaces.js +290 -0
  250. package/lib/types/effortPrefs.d.ts +1 -1
  251. package/lib/types/effortPrefs.js +3 -3
  252. package/lib/types/history.js +2 -2
  253. package/lib/types/hooks/useBlink.d.ts +1 -1
  254. package/lib/types/hooks/useBlink.js +1 -1
  255. package/lib/types/i18n.d.ts +977 -36
  256. package/lib/types/i18n.d.ts.map +1 -1
  257. package/lib/types/i18n.js +307 -30
  258. package/lib/types/index.d.ts +1 -69
  259. package/lib/types/index.d.ts.map +1 -1
  260. package/lib/types/index.js +3 -31
  261. package/lib/types/ink/components/App.d.ts.map +1 -1
  262. package/lib/types/ink/components/App.js +33 -19
  263. package/lib/types/ink/dom.d.ts +15 -0
  264. package/lib/types/ink/dom.d.ts.map +1 -1
  265. package/lib/types/ink/dom.js +32 -0
  266. package/lib/types/ink/hooks/use-input.d.ts.map +1 -1
  267. package/lib/types/ink/hooks/use-input.js +8 -0
  268. package/lib/types/ink/hooks/use-terminal-size.d.ts +1 -1
  269. package/lib/types/ink/hooks/use-terminal-size.js +1 -1
  270. package/lib/types/ink/ink.d.ts.map +1 -1
  271. package/lib/types/ink/ink.js +109 -28
  272. package/lib/types/ink/input-suppression.d.ts +20 -0
  273. package/lib/types/ink/input-suppression.d.ts.map +1 -0
  274. package/lib/types/ink/input-suppression.js +26 -0
  275. package/lib/types/ink/log-update.js +21 -6
  276. package/lib/types/ink/parse-keypress.d.ts +31 -0
  277. package/lib/types/ink/parse-keypress.d.ts.map +1 -1
  278. package/lib/types/ink/parse-keypress.js +442 -8
  279. package/lib/types/ink/terminal-querier.d.ts +5 -1
  280. package/lib/types/ink/terminal-querier.d.ts.map +1 -1
  281. package/lib/types/ink/terminal-querier.js +27 -3
  282. package/lib/types/ink/terminal.d.ts +18 -0
  283. package/lib/types/ink/terminal.d.ts.map +1 -1
  284. package/lib/types/ink/terminal.js +32 -4
  285. package/lib/types/ink/termio/csi.d.ts +10 -0
  286. package/lib/types/ink/termio/csi.d.ts.map +1 -1
  287. package/lib/types/ink/termio/csi.js +20 -0
  288. package/lib/types/ink/termio/tokenize.js +10 -0
  289. package/lib/types/modelPrefs.d.ts +1 -1
  290. package/lib/types/modelPrefs.js +3 -3
  291. package/lib/types/presetPrefs.d.ts +1 -1
  292. package/lib/types/presetPrefs.js +3 -3
  293. package/lib/types/screens/Chat.d.ts +20 -4
  294. package/lib/types/screens/Chat.d.ts.map +1 -1
  295. package/lib/types/screens/Chat.js +655 -55
  296. package/lib/types/screens/StatusLine.d.ts +17 -2
  297. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  298. package/lib/types/screens/StatusLine.js +12 -4
  299. package/lib/types/screens/TrajectoryScene.d.ts +16 -0
  300. package/lib/types/screens/TrajectoryScene.d.ts.map +1 -0
  301. package/lib/types/screens/TrajectoryScene.js +305 -0
  302. package/lib/types/sessionHistory.d.ts +9 -1
  303. package/lib/types/sessionHistory.d.ts.map +1 -1
  304. package/lib/types/sessionHistory.js +56 -16
  305. package/lib/types/sessionModes.d.ts +29 -0
  306. package/lib/types/sessionModes.d.ts.map +1 -0
  307. package/lib/types/sessionModes.js +45 -0
  308. package/lib/types/theme.d.ts +27 -3
  309. package/lib/types/theme.d.ts.map +1 -1
  310. package/lib/types/theme.js +48 -4
  311. package/lib/types/themePrefs.d.ts +3 -3
  312. package/lib/types/themePrefs.js +5 -5
  313. package/lib/types/trajectory/format.d.ts +100 -0
  314. package/lib/types/trajectory/format.d.ts.map +1 -0
  315. package/lib/types/trajectory/format.js +213 -0
  316. package/lib/types/trajectory/motion.d.ts +99 -0
  317. package/lib/types/trajectory/motion.d.ts.map +1 -0
  318. package/lib/types/trajectory/motion.js +143 -0
  319. package/lib/types/trajectory/query.d.ts +83 -0
  320. package/lib/types/trajectory/query.d.ts.map +1 -0
  321. package/lib/types/trajectory/query.js +187 -0
  322. package/lib/types/trajectoryPrefs.d.ts +36 -0
  323. package/lib/types/trajectoryPrefs.d.ts.map +1 -0
  324. package/lib/types/trajectoryPrefs.js +65 -0
  325. package/lib/types/update.d.ts +3 -3
  326. package/lib/types/update.d.ts.map +1 -1
  327. package/lib/types/update.js +18 -7
  328. package/lib/types/utils/clipboard.d.ts +101 -29
  329. package/lib/types/utils/clipboard.d.ts.map +1 -1
  330. package/lib/types/utils/clipboard.js +533 -55
  331. package/lib/types/utils/debug.d.ts +1 -1
  332. package/lib/types/utils/debug.js +2 -2
  333. package/lib/types/utils/execFileNoThrow.d.ts.map +1 -1
  334. package/lib/types/utils/execFileNoThrow.js +16 -6
  335. package/lib/types/utils/externalEditor.d.ts +115 -0
  336. package/lib/types/utils/externalEditor.d.ts.map +1 -0
  337. package/lib/types/utils/externalEditor.js +270 -0
  338. package/lib/types/utils/fullscreen.d.ts +2 -2
  339. package/lib/types/utils/fullscreen.js +3 -3
  340. package/lib/types/utils/loaded-context.d.ts +1 -1
  341. package/lib/types/utils/loaded-context.d.ts.map +1 -1
  342. package/lib/types/utils/modifiers.d.ts +24 -0
  343. package/lib/types/utils/modifiers.d.ts.map +1 -1
  344. package/lib/types/utils/modifiers.js +27 -0
  345. package/lib/types/utils/paths.d.ts +45 -0
  346. package/lib/types/utils/paths.d.ts.map +1 -0
  347. package/lib/types/utils/paths.js +69 -0
  348. package/lib/types/utils/shellQuote.d.ts +14 -0
  349. package/lib/types/utils/shellQuote.d.ts.map +1 -0
  350. package/lib/types/utils/shellQuote.js +39 -0
  351. package/lib/types/utils/workspaceRoot.d.ts +21 -0
  352. package/lib/types/utils/workspaceRoot.d.ts.map +1 -0
  353. package/lib/types/utils/workspaceRoot.js +47 -0
  354. package/lib/types/workspaces.d.ts +3 -0
  355. package/lib/types/workspaces.d.ts.map +1 -0
  356. package/lib/types/workspaces.js +4 -0
  357. package/package.json +26 -8
  358. package/lib/types/approvals.d.ts.map +0 -1
  359. package/lib/types/channel.d.ts.map +0 -1
  360. package/lib/types/childStderr.d.ts.map +0 -1
  361. package/lib/types/compat/index.d.ts +0 -20
  362. package/lib/types/compat/index.d.ts.map +0 -1
  363. package/lib/types/compat/sessionLog.d.ts +0 -40
  364. package/lib/types/compat/sessionLog.d.ts.map +0 -1
  365. package/lib/types/compat/sessionLog.js +0 -226
  366. package/lib/types/invariant.d.ts.map +0 -1
  367. package/lib/types/packaged-skills.d.ts.map +0 -1
  368. package/lib/types/plugin.d.ts.map +0 -1
  369. package/lib/types/presets.d.ts.map +0 -1
  370. package/lib/types/questions.d.ts.map +0 -1
  371. /package/lib/types/{approvals.d.ts → dsh-adapter/approvals.d.ts} +0 -0
  372. /package/lib/types/{approvals.js → dsh-adapter/approvals.js} +0 -0
  373. /package/lib/types/{childStderr.d.ts → dsh-adapter/childStderr.d.ts} +0 -0
  374. /package/lib/types/{invariant.d.ts → dsh-adapter/invariant.d.ts} +0 -0
  375. /package/lib/types/{invariant.js → dsh-adapter/invariant.js} +0 -0
  376. /package/lib/types/{packaged-skills.d.ts → dsh-adapter/packaged-skills.d.ts} +0 -0
  377. /package/lib/types/{packaged-skills.js → dsh-adapter/packaged-skills.js} +0 -0
  378. /package/lib/types/{presets.d.ts → dsh-adapter/presets.d.ts} +0 -0
  379. /package/lib/types/{presets.js → dsh-adapter/presets.js} +0 -0
@@ -10,19 +10,29 @@ import { spawn } from 'node:child_process';
10
10
  export function execFileNoThrow(file, args, options) {
11
11
  return new Promise(resolve => {
12
12
  const child = spawn(file, args ?? [], { timeout: options?.timeout, cwd: options?.cwd });
13
- let stdout = '';
14
- let stderr = '';
13
+ // Collect raw bytes and decode once at close: per-chunk toString() splits
14
+ // multi-byte UTF-8 characters straddling a chunk boundary into U+FFFD.
15
+ const stdoutChunks = [];
16
+ const stderrChunks = [];
15
17
  child.stdout.on('data', (chunk) => {
16
- stdout += chunk.toString();
18
+ stdoutChunks.push(chunk);
17
19
  });
18
20
  child.stderr.on('data', (chunk) => {
19
- stderr += chunk.toString();
21
+ stderrChunks.push(chunk);
20
22
  });
21
23
  child.on('error', () => {
22
- resolve({ code: 1, stdout, stderr });
24
+ resolve({
25
+ code: 1,
26
+ stdout: Buffer.concat(stdoutChunks).toString('utf8'),
27
+ stderr: Buffer.concat(stderrChunks).toString('utf8'),
28
+ });
23
29
  });
24
30
  child.on('close', code => {
25
- resolve({ code, stdout, stderr });
31
+ resolve({
32
+ code,
33
+ stdout: Buffer.concat(stdoutChunks).toString('utf8'),
34
+ stderr: Buffer.concat(stderrChunks).toString('utf8'),
35
+ });
26
36
  });
27
37
  if (options?.input !== undefined)
28
38
  child.stdin.write(options.input);
@@ -0,0 +1,115 @@
1
+ /**
2
+ * External editor round-trip for the prompt input (issue #123): Ctrl+X dumps
3
+ * the current draft into a temp file, hands the terminal to `$VISUAL` /
4
+ * `$EDITOR` (nvim, vim, nano, `code --wait`, …), and returns the saved text
5
+ * for the input to adopt.
6
+ *
7
+ * Terminal handover reuses the Ink core's editor handoff pair —
8
+ * `enterAlternateScreen()` pauses rendering, suspends raw-mode stdin, and
9
+ * drops the extended key reporting that non-CSI-u editors (nano) choke on;
10
+ * `exitAlternateScreen()` re-enters the alt screen (vim's rmcup pops back to
11
+ * the main screen on quit), repaints, and resumes stdin. See ink.tsx. The
12
+ * saved file is read back BEFORE stdin is resumed: resuming earlier would
13
+ * let keystrokes typed right at editor exit race the prompt's `setValue`
14
+ * and get overwritten. The restore is attempted whenever the handover was
15
+ * attempted (a partially-failed enter still gets an exit pass), and a
16
+ * failing restore never overrides the outcome.
17
+ *
18
+ * Editor resolution order mirrors readline's edit-and-execute-command:
19
+ * `$VISUAL` → `$EDITOR` → `vi` on POSIX (always present). Windows has no
20
+ * console-editor guarantee and `notepad` does not block, so an unresolved
21
+ * editor there reports `unavailable` and the UI asks the user to set
22
+ * `$EDITOR`. The variable may carry arguments (`EDITOR="code --wait"`), so
23
+ * the command line is split quote-aware before spawning.
24
+ *
25
+ * Windows launch: libuv resolves bare names to `.exe` on PATH but will NOT
26
+ * execute `.cmd`/`.bat` shims (VS Code's `code` on PATH is `code.cmd`), and
27
+ * `spawn(..., {shell: true})` with arguments triggers DEP0190 on Node 24+.
28
+ * So bare commands are resolved against PATH/PATHEXT up front, and shim
29
+ * scripts go through an explicit `$comspec /d /s /c` whose payload is built
30
+ * with the cross-spawn quoting protocol (vendored in shellQuote.ts) and
31
+ * passed with `windowsVerbatimArguments: true` — without verbatim, libuv
32
+ * re-quotes the already-quoted payload and corrupts paths containing
33
+ * spaces (a stock VS Code install path has them).
34
+ */
35
+ /**
36
+ * Outcome of one editor round-trip; the caller maps these to UI feedback:
37
+ * - `edited`: the saved content differs from the draft — adopt `text`
38
+ * - `unchanged`: the file matches the draft (modulo newline convention), or
39
+ * the editor exited non-zero (`:cq` abort semantics) — keep the draft
40
+ * - `unavailable`: no editor could be resolved (Windows without `$EDITOR`)
41
+ * - `failed`: the editor process or the temp-file round-trip errored
42
+ * (`message` names the failed command or carries the fs error)
43
+ */
44
+ export type EditorOutcome = {
45
+ kind: 'edited';
46
+ text: string;
47
+ } | {
48
+ kind: 'unchanged';
49
+ } | {
50
+ kind: 'unavailable';
51
+ } | {
52
+ kind: 'failed';
53
+ message: string;
54
+ };
55
+ /**
56
+ * Split an `$EDITOR`-style command line into argv, honoring single/double
57
+ * quotes (`code --wait`, `"C:\Program Files\...\nvim.exe" -f`).
58
+ */
59
+ export declare function splitEditorCommand(commandLine: string): string[];
60
+ /**
61
+ * Resolve the editor argv from the environment. `$VISUAL` wins over
62
+ * `$EDITOR` (readline convention); POSIX falls back to `vi`, Windows has no
63
+ * blocking console editor fallback and returns undefined. `platform` is a
64
+ * parameter so the Windows branch is unit-testable from CI's Linux runners.
65
+ */
66
+ export declare function resolveEditorCommand(env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): string[] | undefined;
67
+ /**
68
+ * Windows shim resolution: a bare command like `code` usually lives on PATH
69
+ * as `code.cmd`, which libuv refuses to execute directly. Walk PATH with
70
+ * PATHEXT (case-insensitive on Windows; both casings tried for tests on
71
+ * case-sensitive filesystems) and report whether the resolved file needs
72
+ * cmd.exe to run. Commands carrying an explicit extension are used as-is;
73
+ * unresolved names fall back to the bare command (spawn then resolves
74
+ * `.exe`, or fails into the `failed` outcome).
75
+ */
76
+ export declare function resolveWindowsShim(command: string, env?: NodeJS.ProcessEnv): {
77
+ command: string;
78
+ viaCmd: boolean;
79
+ };
80
+ /**
81
+ * Build the `comspec /d /s /c` spawn descriptor for a `.cmd`/`.bat` editor,
82
+ * following the cross-spawn protocol: the command is normalized first
83
+ * (explicit forward-slash paths like `C:/Program Files/.../code.cmd` must
84
+ * become backslash form — cross-spawn's path.normalize step, without which
85
+ * Windows can ENOENT), then command and arguments are escaped, joined, and
86
+ * wrapped in one pair of quotes (`/s` strips exactly those), and passed
87
+ * with `windowsVerbatimArguments` so libuv does not re-quote the payload.
88
+ * Exported for tests — the assembly is pure.
89
+ */
90
+ export declare function buildCmdExeSpawn(command: string, args: readonly string[], env?: NodeJS.ProcessEnv): {
91
+ file: string;
92
+ args: string[];
93
+ verbatim: true;
94
+ };
95
+ /**
96
+ * Edit `draft` in the user's editor and report what happened. Never throws:
97
+ * every filesystem, spawn, or terminal-restore failure maps to a `failed`
98
+ * outcome (or is swallowed in the finally) so the UI notifies instead of
99
+ * dying on an unhandled rejection.
100
+ *
101
+ * The Ink instance is looked up lazily (same pattern as Chat's Ctrl+L
102
+ * redraw) so the util stays usable in tests and non-TTY contexts: without a
103
+ * live instance the handover escapes are skipped and the editor simply
104
+ * inherits stdio.
105
+ *
106
+ * Newline handling: the saved file is compared against the draft with BOTH
107
+ * sides CRLF-normalized, so an editor that only converts line endings (or
108
+ * a draft that already carries `\r\n`) never counts as an edit. Otherwise
109
+ * ONE trailing newline is stripped when the normalized draft did not end
110
+ * with one — that is the terminating newline editors append on save, not
111
+ * user content. Trailing blank lines the user actually added (or had in
112
+ * the draft, e.g. from Shift+Enter) survive untouched.
113
+ */
114
+ export declare function editInExternalEditor(draft: string): Promise<EditorOutcome>;
115
+ //# sourceMappingURL=externalEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"externalEditor.d.ts","sourceRoot":"","sources":["../../../src/utils/externalEditor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAUH;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAEvC;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CA0BhE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,MAAM,EAAE,GAAG,SAAS,CAOtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAqBtC;AAKD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,IAAI,CAAA;CAAE,CAalD;AA8CD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAsDhF"}
@@ -0,0 +1,270 @@
1
+ /**
2
+ * External editor round-trip for the prompt input (issue #123): Ctrl+X dumps
3
+ * the current draft into a temp file, hands the terminal to `$VISUAL` /
4
+ * `$EDITOR` (nvim, vim, nano, `code --wait`, …), and returns the saved text
5
+ * for the input to adopt.
6
+ *
7
+ * Terminal handover reuses the Ink core's editor handoff pair —
8
+ * `enterAlternateScreen()` pauses rendering, suspends raw-mode stdin, and
9
+ * drops the extended key reporting that non-CSI-u editors (nano) choke on;
10
+ * `exitAlternateScreen()` re-enters the alt screen (vim's rmcup pops back to
11
+ * the main screen on quit), repaints, and resumes stdin. See ink.tsx. The
12
+ * saved file is read back BEFORE stdin is resumed: resuming earlier would
13
+ * let keystrokes typed right at editor exit race the prompt's `setValue`
14
+ * and get overwritten. The restore is attempted whenever the handover was
15
+ * attempted (a partially-failed enter still gets an exit pass), and a
16
+ * failing restore never overrides the outcome.
17
+ *
18
+ * Editor resolution order mirrors readline's edit-and-execute-command:
19
+ * `$VISUAL` → `$EDITOR` → `vi` on POSIX (always present). Windows has no
20
+ * console-editor guarantee and `notepad` does not block, so an unresolved
21
+ * editor there reports `unavailable` and the UI asks the user to set
22
+ * `$EDITOR`. The variable may carry arguments (`EDITOR="code --wait"`), so
23
+ * the command line is split quote-aware before spawning.
24
+ *
25
+ * Windows launch: libuv resolves bare names to `.exe` on PATH but will NOT
26
+ * execute `.cmd`/`.bat` shims (VS Code's `code` on PATH is `code.cmd`), and
27
+ * `spawn(..., {shell: true})` with arguments triggers DEP0190 on Node 24+.
28
+ * So bare commands are resolved against PATH/PATHEXT up front, and shim
29
+ * scripts go through an explicit `$comspec /d /s /c` whose payload is built
30
+ * with the cross-spawn quoting protocol (vendored in shellQuote.ts) and
31
+ * passed with `windowsVerbatimArguments: true` — without verbatim, libuv
32
+ * re-quotes the already-quoted payload and corrupts paths containing
33
+ * spaces (a stock VS Code install path has them).
34
+ */
35
+ import { spawn } from 'node:child_process';
36
+ import { existsSync } from 'node:fs';
37
+ import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
38
+ import { tmpdir } from 'node:os';
39
+ import { delimiter, join, win32 } from 'node:path';
40
+ import instances from '../ink/instances.js';
41
+ import { cmdEscapeArgument, cmdEscapeCommand } from './shellQuote.js';
42
+ /**
43
+ * Split an `$EDITOR`-style command line into argv, honoring single/double
44
+ * quotes (`code --wait`, `"C:\Program Files\...\nvim.exe" -f`).
45
+ */
46
+ export function splitEditorCommand(commandLine) {
47
+ const args = [];
48
+ let current = '';
49
+ let quote = null;
50
+ let hasToken = false;
51
+ for (const ch of commandLine) {
52
+ if (quote !== null) {
53
+ if (ch === quote)
54
+ quote = null;
55
+ else
56
+ current += ch;
57
+ continue;
58
+ }
59
+ if (ch === '"' || ch === "'") {
60
+ quote = ch;
61
+ hasToken = true;
62
+ continue;
63
+ }
64
+ if (/\s/.test(ch)) {
65
+ if (current !== '' || hasToken)
66
+ args.push(current);
67
+ current = '';
68
+ hasToken = false;
69
+ continue;
70
+ }
71
+ current += ch;
72
+ }
73
+ if (current !== '' || hasToken)
74
+ args.push(current);
75
+ return args;
76
+ }
77
+ /**
78
+ * Resolve the editor argv from the environment. `$VISUAL` wins over
79
+ * `$EDITOR` (readline convention); POSIX falls back to `vi`, Windows has no
80
+ * blocking console editor fallback and returns undefined. `platform` is a
81
+ * parameter so the Windows branch is unit-testable from CI's Linux runners.
82
+ */
83
+ export function resolveEditorCommand(env = process.env, platform = process.platform) {
84
+ const raw = (env.VISUAL ?? '').trim() || (env.EDITOR ?? '').trim();
85
+ if (raw !== '') {
86
+ const args = splitEditorCommand(raw);
87
+ return args.length > 0 ? args : undefined;
88
+ }
89
+ return platform === 'win32' ? undefined : ['vi'];
90
+ }
91
+ /**
92
+ * Windows shim resolution: a bare command like `code` usually lives on PATH
93
+ * as `code.cmd`, which libuv refuses to execute directly. Walk PATH with
94
+ * PATHEXT (case-insensitive on Windows; both casings tried for tests on
95
+ * case-sensitive filesystems) and report whether the resolved file needs
96
+ * cmd.exe to run. Commands carrying an explicit extension are used as-is;
97
+ * unresolved names fall back to the bare command (spawn then resolves
98
+ * `.exe`, or fails into the `failed` outcome).
99
+ */
100
+ export function resolveWindowsShim(command, env = process.env) {
101
+ if (/\.[a-z0-9]+$/i.test(command)) {
102
+ return { command, viaCmd: /\.(cmd|bat)$/i.test(command) };
103
+ }
104
+ const extensions = (env.PATHEXT ?? '.COM;.EXE;.BAT;.CMD')
105
+ .split(';')
106
+ .map(ext => ext.trim())
107
+ .filter(ext => ext !== '');
108
+ const pathValue = env.PATH ?? env.Path ?? env.path ?? '';
109
+ for (const dir of pathValue.split(delimiter)) {
110
+ if (dir === '')
111
+ continue;
112
+ for (const ext of extensions) {
113
+ for (const casing of [ext, ext.toLowerCase()]) {
114
+ const candidate = join(dir, command + casing);
115
+ if (existsSync(candidate)) {
116
+ return { command: candidate, viaCmd: /\.(cmd|bat)$/i.test(candidate) };
117
+ }
118
+ }
119
+ }
120
+ }
121
+ return { command, viaCmd: false };
122
+ }
123
+ /** npm-generated node shims re-invoke node, parsing the line a second time. */
124
+ const CMD_SHIM_RE = /node_modules[\\/]\.bin[\\/][^\\/]+\.cmd$/i;
125
+ /**
126
+ * Build the `comspec /d /s /c` spawn descriptor for a `.cmd`/`.bat` editor,
127
+ * following the cross-spawn protocol: the command is normalized first
128
+ * (explicit forward-slash paths like `C:/Program Files/.../code.cmd` must
129
+ * become backslash form — cross-spawn's path.normalize step, without which
130
+ * Windows can ENOENT), then command and arguments are escaped, joined, and
131
+ * wrapped in one pair of quotes (`/s` strips exactly those), and passed
132
+ * with `windowsVerbatimArguments` so libuv does not re-quote the payload.
133
+ * Exported for tests — the assembly is pure.
134
+ */
135
+ export function buildCmdExeSpawn(command, args, env = process.env) {
136
+ const normalized = win32.normalize(command);
137
+ const line = [
138
+ cmdEscapeCommand(normalized),
139
+ ...args.map(arg => cmdEscapeArgument(arg, CMD_SHIM_RE.test(normalized))),
140
+ ].join(' ');
141
+ return {
142
+ // `||`, not `??`: a present-but-empty ComSpec must fall back too
143
+ // (cross-spawn semantics); spawning an empty file name fails outright.
144
+ file: env.comspec || 'cmd.exe',
145
+ args: ['/d', '/s', '/c', `"${line}"`],
146
+ verbatim: true,
147
+ };
148
+ }
149
+ /**
150
+ * Run the editor to completion with the terminal attached; resolves to the
151
+ * exit code, or -1 when the process could not start — including a
152
+ * SYNCHRONOUS spawn failure (e.g. an empty command string), which would
153
+ * otherwise reject the promise and skip every cleanup step.
154
+ */
155
+ function runEditor(argv, file) {
156
+ return new Promise(resolve => {
157
+ let settled = false;
158
+ const finish = (code) => {
159
+ if (settled)
160
+ return;
161
+ settled = true;
162
+ resolve(code);
163
+ };
164
+ let child;
165
+ try {
166
+ if (process.platform === 'win32') {
167
+ const shim = resolveWindowsShim(argv[0]);
168
+ if (shim.viaCmd) {
169
+ const cmd = buildCmdExeSpawn(shim.command, [...argv.slice(1), file]);
170
+ child = spawn(cmd.file, cmd.args, {
171
+ stdio: 'inherit',
172
+ windowsVerbatimArguments: cmd.verbatim,
173
+ });
174
+ }
175
+ else {
176
+ child = spawn(shim.command, [...argv.slice(1), file], { stdio: 'inherit' });
177
+ }
178
+ }
179
+ else {
180
+ child = spawn(argv[0], [...argv.slice(1), file], { stdio: 'inherit' });
181
+ }
182
+ }
183
+ catch {
184
+ finish(-1);
185
+ return;
186
+ }
187
+ child.once('error', () => finish(-1));
188
+ child.once('close', code => finish(code ?? 1));
189
+ });
190
+ }
191
+ /** Error text for the `failed` outcome, err.message when available. */
192
+ function errorMessage(error) {
193
+ return error instanceof Error ? error.message : String(error);
194
+ }
195
+ /**
196
+ * Edit `draft` in the user's editor and report what happened. Never throws:
197
+ * every filesystem, spawn, or terminal-restore failure maps to a `failed`
198
+ * outcome (or is swallowed in the finally) so the UI notifies instead of
199
+ * dying on an unhandled rejection.
200
+ *
201
+ * The Ink instance is looked up lazily (same pattern as Chat's Ctrl+L
202
+ * redraw) so the util stays usable in tests and non-TTY contexts: without a
203
+ * live instance the handover escapes are skipped and the editor simply
204
+ * inherits stdio.
205
+ *
206
+ * Newline handling: the saved file is compared against the draft with BOTH
207
+ * sides CRLF-normalized, so an editor that only converts line endings (or
208
+ * a draft that already carries `\r\n`) never counts as an edit. Otherwise
209
+ * ONE trailing newline is stripped when the normalized draft did not end
210
+ * with one — that is the terminating newline editors append on save, not
211
+ * user content. Trailing blank lines the user actually added (or had in
212
+ * the draft, e.g. from Shift+Enter) survive untouched.
213
+ */
214
+ export async function editInExternalEditor(draft) {
215
+ const argv = resolveEditorCommand();
216
+ if (argv === undefined)
217
+ return { kind: 'unavailable' };
218
+ const ink = instances.get(process.stdout) ??
219
+ // Test harnesses render onto a fake stdout — fall back to the process's
220
+ // single live instance so the handover path stays exercisable there.
221
+ (instances.size === 1 ? [...instances.values()][0] : undefined);
222
+ let handed = false;
223
+ let dir;
224
+ try {
225
+ dir = await mkdtemp(join(tmpdir(), 'dsh-tui-prompt-'));
226
+ // .md so markdown-aware editors highlight the draft like a chat message.
227
+ const file = join(dir, 'input.md');
228
+ await writeFile(file, draft, 'utf8');
229
+ // Mark the handover as attempted BEFORE entering: if enter fails after
230
+ // suspending stdin, the finally must still run the restore pass.
231
+ handed = ink !== undefined;
232
+ ink?.enterAlternateScreen();
233
+ const code = await runEditor(argv, file);
234
+ // Read back BEFORE the finally resumes stdin — keystrokes typed the
235
+ // moment the editor exits must not race the prompt adopting the result.
236
+ const saved = await readFile(file, 'utf8').catch(() => null);
237
+ if (code === -1)
238
+ return { kind: 'failed', message: argv[0] };
239
+ if (code !== 0 || saved === null)
240
+ return { kind: 'unchanged' };
241
+ const normalized = saved.replace(/\r\n/g, '\n');
242
+ const draftNormalized = draft.replace(/\r\n/g, '\n');
243
+ if (normalized === draftNormalized)
244
+ return { kind: 'unchanged' };
245
+ const text = !draftNormalized.endsWith('\n') && normalized.endsWith('\n')
246
+ ? normalized.slice(0, -1)
247
+ : normalized;
248
+ return text === draftNormalized ? { kind: 'unchanged' } : { kind: 'edited', text };
249
+ }
250
+ catch (error) {
251
+ return { kind: 'failed', message: errorMessage(error) };
252
+ }
253
+ finally {
254
+ // Cleanup runs before the restore: when the finally ends, stdin must
255
+ // come back to a fully settled state. Both steps are best-effort — a
256
+ // failure here never overrides the outcome produced above.
257
+ if (dir !== undefined) {
258
+ await rm(dir, { recursive: true, force: true }).catch(() => { });
259
+ }
260
+ if (handed) {
261
+ try {
262
+ ink?.exitAlternateScreen();
263
+ }
264
+ catch {
265
+ // A stuck alt screen is visible to the user; a rejection on top of
266
+ // a valid outcome is strictly worse — swallow and keep the outcome.
267
+ }
268
+ }
269
+ }
270
+ }
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Whether mouse click handling is disabled for the ported Ink core. dsh-tui
3
- * reads its own env flag (`CC_TUI_DISABLE_MOUSE`); the original module
3
+ * reads its own env flag (`DSH_TUI_DISABLE_MOUSE`); the original module
4
4
  * consulted Claude Code's fullscreen state.
5
- * @returns True when CC_TUI_DISABLE_MOUSE is set to a truthy value.
5
+ * @returns True when DSH_TUI_DISABLE_MOUSE is set to a truthy value.
6
6
  */
7
7
  export declare function isMouseClicksDisabled(): boolean;
8
8
  //# sourceMappingURL=fullscreen.d.ts.map
@@ -1,10 +1,10 @@
1
1
  import { isEnvTruthy } from './envUtils.js';
2
2
  /**
3
3
  * Whether mouse click handling is disabled for the ported Ink core. dsh-tui
4
- * reads its own env flag (`CC_TUI_DISABLE_MOUSE`); the original module
4
+ * reads its own env flag (`DSH_TUI_DISABLE_MOUSE`); the original module
5
5
  * consulted Claude Code's fullscreen state.
6
- * @returns True when CC_TUI_DISABLE_MOUSE is set to a truthy value.
6
+ * @returns True when DSH_TUI_DISABLE_MOUSE is set to a truthy value.
7
7
  */
8
8
  export function isMouseClicksDisabled() {
9
- return isEnvTruthy(process.env.CC_TUI_DISABLE_MOUSE);
9
+ return isEnvTruthy(process.env.DSH_TUI_DISABLE_MOUSE);
10
10
  }
@@ -1,4 +1,4 @@
1
- import type { LoadedContext } from '../channel.js';
1
+ import type { LoadedContext } from '../dsh-adapter/channel.js';
2
2
  /** Per-entry display cap: the panel shows the beginning of long texts. */
3
3
  export declare const CONTEXT_ENTRY_MAX_CHARS = 800;
4
4
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"loaded-context.d.ts","sourceRoot":"","sources":["../../../src/utils/loaded-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAGlD,0EAA0E;AAC1E,eAAO,MAAM,uBAAuB,MAAM,CAAA;AAE1C;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAA0B,GAAG,MAAM,CAGvF;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAQrE"}
1
+ {"version":3,"file":"loaded-context.d.ts","sourceRoot":"","sources":["../../../src/utils/loaded-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAG9D,0EAA0E;AAC1E,eAAO,MAAM,uBAAuB,MAAM,CAAA;AAE1C;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAA0B,GAAG,MAAM,CAGvF;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAQrE"}
@@ -16,4 +16,28 @@ export declare function isMod(key: {
16
16
  * "ctrl+" everywhere else. Pair with the bare key, e.g. `${modLabel}o`.
17
17
  */
18
18
  export declare const modLabel: string;
19
+ /**
20
+ * Modal-confirm guard. Since #110 the input pipeline can deliver Enter WITH
21
+ * modifiers: Option+Enter arrives as meta+return (ESC CR), and on
22
+ * extended-keys terminals (kitty CSI-u / modifyOtherKeys) Shift/Ctrl+Enter
23
+ * arrive as return+modifier. A bare `key.return` in a decision dialog would
24
+ * let those commit by accident — approving a permission escalation or
25
+ * confirming an irreversible session delete when the user only wanted a
26
+ * newline. Only a modifier-free Enter may commit a modal.
27
+ */
28
+ export declare function isPlainReturn(key: {
29
+ return?: boolean;
30
+ ctrl?: boolean;
31
+ meta?: boolean;
32
+ shift?: boolean;
33
+ super?: boolean;
34
+ }): boolean;
35
+ /**
36
+ * Modal Enter recognition across parsed key events and Windows ConPTY's raw
37
+ * CR/LF fallback. PromptInput already handled both forms; shared modal
38
+ * pickers must do the same or their UI can render while Enter appears inert.
39
+ */
40
+ export declare function isPlainReturnInput(input: string, key: Parameters<typeof isPlainReturn>[0] & {
41
+ isPasted?: boolean;
42
+ }): boolean;
19
43
  //# sourceMappingURL=modifiers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"modifiers.d.ts","sourceRoot":"","sources":["../../../src/utils/modifiers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,eAAO,MAAM,KAAK,SAAgC,CAAA;AAElD,yEAAyE;AACzE,wBAAgB,KAAK,CAAC,GAAG,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAEvE;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,QAAwB,CAAA"}
1
+ {"version":3,"file":"modifiers.d.ts","sourceRoot":"","sources":["../../../src/utils/modifiers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,eAAO,MAAM,KAAK,SAAgC,CAAA;AAElD,yEAAyE;AACzE,wBAAgB,KAAK,CAAC,GAAG,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAEvE;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,QAAwB,CAAA;AAE7C;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE;IACjC,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,GAAG,OAAO,CAEV;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAChE,OAAO,CAOT"}
@@ -15,3 +15,30 @@ export function isMod(key) {
15
15
  * "ctrl+" everywhere else. Pair with the bare key, e.g. `${modLabel}o`.
16
16
  */
17
17
  export const modLabel = isMac ? '⌘' : 'ctrl+';
18
+ /**
19
+ * Modal-confirm guard. Since #110 the input pipeline can deliver Enter WITH
20
+ * modifiers: Option+Enter arrives as meta+return (ESC CR), and on
21
+ * extended-keys terminals (kitty CSI-u / modifyOtherKeys) Shift/Ctrl+Enter
22
+ * arrive as return+modifier. A bare `key.return` in a decision dialog would
23
+ * let those commit by accident — approving a permission escalation or
24
+ * confirming an irreversible session delete when the user only wanted a
25
+ * newline. Only a modifier-free Enter may commit a modal.
26
+ */
27
+ export function isPlainReturn(key) {
28
+ return !!key.return && !key.ctrl && !key.meta && !key.shift && !key.super;
29
+ }
30
+ /**
31
+ * Modal Enter recognition across parsed key events and Windows ConPTY's raw
32
+ * CR/LF fallback. PromptInput already handled both forms; shared modal
33
+ * pickers must do the same or their UI can render while Enter appears inert.
34
+ */
35
+ export function isPlainReturnInput(input, key) {
36
+ if (isPlainReturn(key))
37
+ return true;
38
+ // Bracketed paste can deliver a chunk that is all line breaks — that is
39
+ // pasted content, not an Enter press, and must never confirm a modal.
40
+ if (key.isPasted === true)
41
+ return false;
42
+ return /^[\r\n]+$/u.test(input)
43
+ && !key.ctrl && !key.meta && !key.shift && !key.super;
44
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Data-directory paths for the dsh-tui profile, renamed from `~/.dsh-cc` to
3
+ * `~/.dsh-tui` (issue #120). On first launch the legacy directory is COPIED
4
+ * (not moved) to the new location; afterwards only the new directory is read
5
+ * and written. The one exception is `resume.txt`, which sessionHistory
6
+ * dual-writes for old launchers — see the launcher contract there.
7
+ *
8
+ * The compiled copy (lib/types/utils/paths.js) is also imported by the bin
9
+ * launcher, mirroring the shellQuote precedent.
10
+ */
11
+ /**
12
+ * The user's home directory. `os.homedir()` first; the USERPROFILE/HOME
13
+ * spellings are the last-resort fallback for stripped-down environments.
14
+ * @returns Absolute home path.
15
+ */
16
+ export declare function homeDir(): string;
17
+ /** Data directory all preferences/history live in (`~/.dsh-tui`). */
18
+ export declare const DATA_DIR: string;
19
+ /** Pre-rename data directory (`~/.dsh-cc`), read only for migration. */
20
+ export declare const LEGACY_DATA_DIR: string;
21
+ /**
22
+ * Copy the legacy data directory to the new location on first launch.
23
+ * A copy (not a move) so old launchers keep working and the user can delete
24
+ * the legacy directory themselves once satisfied. No-op when the legacy
25
+ * directory is absent or the new one already exists.
26
+ * @param legacy - Legacy directory (injectable for tests).
27
+ * @param target - New directory (injectable for tests).
28
+ * @returns True when a migration copy happened.
29
+ */
30
+ export declare function migrateLegacyDataDir(legacy?: string, target?: string): boolean;
31
+ /**
32
+ * Env vars renamed in issue #120 that no longer take effect: old name → new
33
+ * name. `DSH_CC_RESUME_SESSION` is deliberately absent — it remains a valid
34
+ * half of the dual-read launcher contract (see sessionHistory.ts).
35
+ */
36
+ export declare const RENAMED_ENV: Readonly<Record<string, string>>;
37
+ /**
38
+ * Old env-var names still set in the environment (they no longer take
39
+ * effect). Used to print one deprecation line per name before the TUI
40
+ * renders — stderr writes break the fullscreen UI once it is up.
41
+ * @param env - Environment to scan (defaults to process.env; injectable).
42
+ * @returns The legacy names found, in RENAMED_ENV order.
43
+ */
44
+ export declare function detectLegacyEnv(env?: NodeJS.ProcessEnv): string[];
45
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/utils/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH;;;;GAIG;AACH,wBAAgB,OAAO,IAAI,MAAM,CAEhC;AAED,qEAAqE;AACrE,eAAO,MAAM,QAAQ,QAA8B,CAAA;AAEnD,wEAAwE;AACxE,eAAO,MAAM,eAAe,QAA6B,CAAA;AAEzD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,GAAE,MAAwB,EAChC,MAAM,GAAE,MAAiB,GACxB,OAAO,CAIT;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAaxD,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,EAAE,CAEV"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Data-directory paths for the dsh-tui profile, renamed from `~/.dsh-cc` to
3
+ * `~/.dsh-tui` (issue #120). On first launch the legacy directory is COPIED
4
+ * (not moved) to the new location; afterwards only the new directory is read
5
+ * and written. The one exception is `resume.txt`, which sessionHistory
6
+ * dual-writes for old launchers — see the launcher contract there.
7
+ *
8
+ * The compiled copy (lib/types/utils/paths.js) is also imported by the bin
9
+ * launcher, mirroring the shellQuote precedent.
10
+ */
11
+ import { cpSync, existsSync } from 'node:fs';
12
+ import { homedir } from 'node:os';
13
+ import { join } from 'node:path';
14
+ /**
15
+ * The user's home directory. `os.homedir()` first; the USERPROFILE/HOME
16
+ * spellings are the last-resort fallback for stripped-down environments.
17
+ * @returns Absolute home path.
18
+ */
19
+ export function homeDir() {
20
+ return homedir() || process.env.USERPROFILE || process.env.HOME || '';
21
+ }
22
+ /** Data directory all preferences/history live in (`~/.dsh-tui`). */
23
+ export const DATA_DIR = join(homeDir(), '.dsh-tui');
24
+ /** Pre-rename data directory (`~/.dsh-cc`), read only for migration. */
25
+ export const LEGACY_DATA_DIR = join(homeDir(), '.dsh-cc');
26
+ /**
27
+ * Copy the legacy data directory to the new location on first launch.
28
+ * A copy (not a move) so old launchers keep working and the user can delete
29
+ * the legacy directory themselves once satisfied. No-op when the legacy
30
+ * directory is absent or the new one already exists.
31
+ * @param legacy - Legacy directory (injectable for tests).
32
+ * @param target - New directory (injectable for tests).
33
+ * @returns True when a migration copy happened.
34
+ */
35
+ export function migrateLegacyDataDir(legacy = LEGACY_DATA_DIR, target = DATA_DIR) {
36
+ if (!existsSync(legacy) || existsSync(target))
37
+ return false;
38
+ cpSync(legacy, target, { recursive: true });
39
+ return true;
40
+ }
41
+ /**
42
+ * Env vars renamed in issue #120 that no longer take effect: old name → new
43
+ * name. `DSH_CC_RESUME_SESSION` is deliberately absent — it remains a valid
44
+ * half of the dual-read launcher contract (see sessionHistory.ts).
45
+ */
46
+ export const RENAMED_ENV = {
47
+ CC_TUI_THEME: 'DSH_TUI_THEME',
48
+ CC_TUI_LANG: 'DSH_TUI_LANG',
49
+ CC_TUI_PERSONA: 'DSH_TUI_PERSONA',
50
+ CC_TUI_PRESET: 'DSH_TUI_PRESET',
51
+ CC_TUI_DISABLE_MOUSE: 'DSH_TUI_DISABLE_MOUSE',
52
+ CC_TUI_DEBUG: 'DSH_TUI_DEBUG',
53
+ CC_TUI_COMPACT_RATIO: 'DSH_TUI_COMPACT_RATIO',
54
+ CC_TUI_COMPACT_RETAIN: 'DSH_TUI_COMPACT_RETAIN',
55
+ DSH_CC_UPDATED_FROM: 'DSH_TUI_UPDATED_FROM',
56
+ DSH_CC_RENDER_LOG: 'DSH_TUI_RENDER_LOG',
57
+ DSH_CC_SESSION_ROOT: 'DSH_TUI_SESSION_ROOT',
58
+ DSH_CC_WORKSPACE: 'DSH_TUI_WORKSPACE',
59
+ };
60
+ /**
61
+ * Old env-var names still set in the environment (they no longer take
62
+ * effect). Used to print one deprecation line per name before the TUI
63
+ * renders — stderr writes break the fullscreen UI once it is up.
64
+ * @param env - Environment to scan (defaults to process.env; injectable).
65
+ * @returns The legacy names found, in RENAMED_ENV order.
66
+ */
67
+ export function detectLegacyEnv(env = process.env) {
68
+ return Object.keys(RENAMED_ENV).filter(name => env[name] !== undefined);
69
+ }