@deepseek-harness-tui/dsh-tui 0.10.2 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (351) hide show
  1. package/README.md +175 -123
  2. package/bin/dsh-tui.js +748 -22
  3. package/cordis.patch.yml +42 -13
  4. package/cordis.yml +5 -2
  5. package/lib/types/activityPrefs.d.ts +24 -0
  6. package/lib/types/activityPrefs.d.ts.map +1 -1
  7. package/lib/types/activityPrefs.js +50 -1
  8. package/lib/types/adapter/channel/session-projection.d.ts.map +1 -1
  9. package/lib/types/adapter/channel/session-projection.js +2 -0
  10. package/lib/types/adapter/channel/state.d.ts.map +1 -1
  11. package/lib/types/adapter/channel/state.js +3 -1
  12. package/lib/types/adapter/channel/ui-policy.d.ts +4 -1
  13. package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
  14. package/lib/types/adapter/channel/ui-policy.js +6 -2
  15. package/lib/types/adapter/kernel/host-facade.d.ts.map +1 -1
  16. package/lib/types/adapter/kernel/host-facade.js +1 -0
  17. package/lib/types/adapter/kernel/replay.d.ts.map +1 -1
  18. package/lib/types/adapter/kernel/replay.js +3 -0
  19. package/lib/types/adapter/kernel/runtime.d.ts.map +1 -1
  20. package/lib/types/adapter/kernel/runtime.js +2 -0
  21. package/lib/types/adapter/kernel/slices/workspace.d.ts.map +1 -1
  22. package/lib/types/adapter/kernel/slices/workspace.js +1 -0
  23. package/lib/types/adapter/ports/channel-ui.d.ts +29 -5
  24. package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
  25. package/lib/types/adapter/ports/channel-view.d.ts +66 -12
  26. package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
  27. package/lib/types/adapter/ports/channel-workspace.d.ts +23 -0
  28. package/lib/types/adapter/ports/channel-workspace.d.ts.map +1 -1
  29. package/lib/types/adapter/ports/channel.d.ts +4 -1
  30. package/lib/types/adapter/ports/channel.d.ts.map +1 -1
  31. package/lib/types/adapter/ports/workspace.d.ts +2 -0
  32. package/lib/types/adapter/ports/workspace.d.ts.map +1 -1
  33. package/lib/types/adapter/upstream/workspace-driver.d.ts.map +1 -1
  34. package/lib/types/adapter/upstream/workspace-driver.js +10 -2
  35. package/lib/types/commands.d.ts.map +1 -1
  36. package/lib/types/commands.js +1 -0
  37. package/lib/types/components/ActivityLine.d.ts +7 -2
  38. package/lib/types/components/ActivityLine.d.ts.map +1 -1
  39. package/lib/types/components/ActivityLine.js +0 -8
  40. package/lib/types/components/ContextBarView.d.ts +15 -7
  41. package/lib/types/components/ContextBarView.d.ts.map +1 -1
  42. package/lib/types/components/ContextBarView.js +26 -22
  43. package/lib/types/components/ImagePreviewOverlay.d.ts.map +1 -1
  44. package/lib/types/components/ImagePreviewOverlay.js +11 -5
  45. package/lib/types/components/Markdown.d.ts +11 -1
  46. package/lib/types/components/Markdown.d.ts.map +1 -1
  47. package/lib/types/components/Markdown.js +20 -2
  48. package/lib/types/components/MermaidDiagram.d.ts +13 -0
  49. package/lib/types/components/MermaidDiagram.d.ts.map +1 -0
  50. package/lib/types/components/MermaidDiagram.js +61 -0
  51. package/lib/types/components/MessageList.d.ts +26 -1
  52. package/lib/types/components/MessageList.d.ts.map +1 -1
  53. package/lib/types/components/MessageList.js +74 -8
  54. package/lib/types/components/PageMargin.d.ts +1 -1
  55. package/lib/types/components/PromptInput.d.ts +37 -1
  56. package/lib/types/components/PromptInput.d.ts.map +1 -1
  57. package/lib/types/components/PromptInput.js +291 -30
  58. package/lib/types/components/ScrollbarGutter.d.ts +20 -5
  59. package/lib/types/components/ScrollbarGutter.d.ts.map +1 -1
  60. package/lib/types/components/ScrollbarGutter.js +88 -10
  61. package/lib/types/components/SplitDiffView.d.ts.map +1 -1
  62. package/lib/types/components/SplitDiffView.js +2 -1
  63. package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
  64. package/lib/types/components/StreamingMarkdown.js +30 -28
  65. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  66. package/lib/types/components/SubagentCard.js +12 -6
  67. package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
  68. package/lib/types/components/SubagentDetailScene.js +8 -3
  69. package/lib/types/components/Tooltip.d.ts.map +1 -1
  70. package/lib/types/components/Tooltip.js +45 -7
  71. package/lib/types/components/design-system/HintLine.d.ts +1 -2
  72. package/lib/types/components/design-system/HintLine.d.ts.map +1 -1
  73. package/lib/types/components/design-system/HintLine.js +1 -2
  74. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +2 -1
  75. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  76. package/lib/types/components/messages/AssistantThinkingMessage.js +2 -1
  77. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +2 -2
  78. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  79. package/lib/types/components/messages/AssistantToolUseMessage.js +30 -26
  80. package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
  81. package/lib/types/components/messages/UserPromptMessage.js +5 -7
  82. package/lib/types/components/messages/useImageInspection.d.ts.map +1 -1
  83. package/lib/types/components/messages/useImageInspection.js +19 -9
  84. package/lib/types/components/promptDraftCache.d.ts +102 -0
  85. package/lib/types/components/promptDraftCache.d.ts.map +1 -0
  86. package/lib/types/components/promptDraftCache.js +76 -0
  87. package/lib/types/components/questions/AskUserQuestionPanel.d.ts +17 -1
  88. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  89. package/lib/types/components/questions/AskUserQuestionPanel.js +40 -7
  90. package/lib/types/components/questions/QuestionMinimizedBar.d.ts +12 -0
  91. package/lib/types/components/questions/QuestionMinimizedBar.d.ts.map +1 -0
  92. package/lib/types/components/questions/QuestionMinimizedBar.js +43 -0
  93. package/lib/types/components/sessions/SessionListRow.d.ts +23 -1
  94. package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
  95. package/lib/types/components/sessions/SessionListRow.js +52 -5
  96. package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts +49 -0
  97. package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts.map +1 -0
  98. package/lib/types/components/workspaces/HomeWorkspaceRow.js +50 -0
  99. package/lib/types/dsh-adapter/activity-store.d.ts +221 -0
  100. package/lib/types/dsh-adapter/activity-store.d.ts.map +1 -0
  101. package/lib/types/dsh-adapter/activity-store.js +359 -0
  102. package/lib/types/dsh-adapter/bundled-presets.d.ts +10 -0
  103. package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -0
  104. package/lib/types/dsh-adapter/bundled-presets.js +80 -0
  105. package/lib/types/dsh-adapter/channel/action-readiness.d.ts +1 -1
  106. package/lib/types/dsh-adapter/channel/action-readiness.d.ts.map +1 -1
  107. package/lib/types/dsh-adapter/channel/action-readiness.js +3 -0
  108. package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts +1 -1
  109. package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts.map +1 -1
  110. package/lib/types/dsh-adapter/channel/agent-view-projection.js +19 -2
  111. package/lib/types/dsh-adapter/channel/background-action.d.ts +1 -1
  112. package/lib/types/dsh-adapter/channel/background-action.d.ts.map +1 -1
  113. package/lib/types/dsh-adapter/channel/background-action.js +53 -29
  114. package/lib/types/dsh-adapter/channel/binding-events.d.ts +8 -6
  115. package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
  116. package/lib/types/dsh-adapter/channel/binding-events.js +5 -4
  117. package/lib/types/dsh-adapter/channel/binding.d.ts +19 -2
  118. package/lib/types/dsh-adapter/channel/binding.d.ts.map +1 -1
  119. package/lib/types/dsh-adapter/channel/binding.js +78 -18
  120. package/lib/types/dsh-adapter/channel/compaction.d.ts +0 -1
  121. package/lib/types/dsh-adapter/channel/compaction.d.ts.map +1 -1
  122. package/lib/types/dsh-adapter/channel/compaction.js +0 -2
  123. package/lib/types/dsh-adapter/channel/composer-images.d.ts +5 -0
  124. package/lib/types/dsh-adapter/channel/composer-images.d.ts.map +1 -1
  125. package/lib/types/dsh-adapter/channel/composer-images.js +105 -6
  126. package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts +8 -0
  127. package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts.map +1 -1
  128. package/lib/types/dsh-adapter/channel/context-bookkeeping.js +3 -2
  129. package/lib/types/dsh-adapter/channel/ide-selection.d.ts +58 -0
  130. package/lib/types/dsh-adapter/channel/ide-selection.d.ts.map +1 -0
  131. package/lib/types/dsh-adapter/channel/ide-selection.js +226 -0
  132. package/lib/types/dsh-adapter/channel/input-delivery.d.ts +6 -1
  133. package/lib/types/dsh-adapter/channel/input-delivery.d.ts.map +1 -1
  134. package/lib/types/dsh-adapter/channel/input-delivery.js +9 -1
  135. package/lib/types/dsh-adapter/channel/local-actions.d.ts +3 -19
  136. package/lib/types/dsh-adapter/channel/local-actions.d.ts.map +1 -1
  137. package/lib/types/dsh-adapter/channel/local-actions.js +2 -1
  138. package/lib/types/dsh-adapter/channel/model-actions.d.ts +4 -1
  139. package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
  140. package/lib/types/dsh-adapter/channel/model-actions.js +82 -6
  141. package/lib/types/dsh-adapter/channel/model-switch.d.ts +1 -2
  142. package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
  143. package/lib/types/dsh-adapter/channel/model-switch.js +49 -31
  144. package/lib/types/dsh-adapter/channel/projection.d.ts +4 -0
  145. package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
  146. package/lib/types/dsh-adapter/channel/projection.js +29 -19
  147. package/lib/types/dsh-adapter/channel/reports.d.ts.map +1 -1
  148. package/lib/types/dsh-adapter/channel/reports.js +4 -12
  149. package/lib/types/dsh-adapter/channel/session-adoption.d.ts +1 -1
  150. package/lib/types/dsh-adapter/channel/session-adoption.d.ts.map +1 -1
  151. package/lib/types/dsh-adapter/channel/session-adoption.js +1 -0
  152. package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
  153. package/lib/types/dsh-adapter/channel/session-fork.js +26 -2
  154. package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts +4 -1
  155. package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts.map +1 -1
  156. package/lib/types/dsh-adapter/channel/session-live-adoption.js +2 -0
  157. package/lib/types/dsh-adapter/channel/session-metadata.d.ts +10 -0
  158. package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
  159. package/lib/types/dsh-adapter/channel/session-metadata.js +6 -4
  160. package/lib/types/dsh-adapter/channel/session-reset.d.ts +1 -1
  161. package/lib/types/dsh-adapter/channel/session-reset.d.ts.map +1 -1
  162. package/lib/types/dsh-adapter/channel/session-reset.js +0 -1
  163. package/lib/types/dsh-adapter/channel/session-resume.d.ts +12 -3
  164. package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
  165. package/lib/types/dsh-adapter/channel/session-resume.js +292 -94
  166. package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
  167. package/lib/types/dsh-adapter/channel/session-rewind.js +34 -16
  168. package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
  169. package/lib/types/dsh-adapter/channel/session-tree-actions.js +19 -3
  170. package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
  171. package/lib/types/dsh-adapter/channel/settings-host.js +4 -3
  172. package/lib/types/dsh-adapter/channel/state.d.ts +6 -1
  173. package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
  174. package/lib/types/dsh-adapter/channel/state.js +3 -3
  175. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts +21 -1
  176. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
  177. package/lib/types/dsh-adapter/channel/subagent-projection.js +173 -6
  178. package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
  179. package/lib/types/dsh-adapter/channel/transcript.js +6 -12
  180. package/lib/types/dsh-adapter/channel/types.d.ts +6 -1
  181. package/lib/types/dsh-adapter/channel/types.d.ts.map +1 -1
  182. package/lib/types/dsh-adapter/channel/workspace-actions.d.ts +4 -1
  183. package/lib/types/dsh-adapter/channel/workspace-actions.d.ts.map +1 -1
  184. package/lib/types/dsh-adapter/channel/workspace-actions.js +41 -1
  185. package/lib/types/dsh-adapter/channel.d.ts +1 -1
  186. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  187. package/lib/types/dsh-adapter/channel.js +82 -20
  188. package/lib/types/dsh-adapter/compat/index.d.ts +1 -1
  189. package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -1
  190. package/lib/types/dsh-adapter/compat/index.js +1 -1
  191. package/lib/types/dsh-adapter/compat/messages.d.ts +15 -0
  192. package/lib/types/dsh-adapter/compat/messages.d.ts.map +1 -0
  193. package/lib/types/dsh-adapter/compat/messages.js +15 -0
  194. package/lib/types/dsh-adapter/compat/sessionLog.d.ts +18 -0
  195. package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -1
  196. package/lib/types/dsh-adapter/compat/sessionLog.js +18 -3
  197. package/lib/types/dsh-adapter/compat/settings.d.ts +35 -0
  198. package/lib/types/dsh-adapter/compat/settings.d.ts.map +1 -0
  199. package/lib/types/dsh-adapter/compat/settings.js +57 -0
  200. package/lib/types/dsh-adapter/compat/shell.d.ts +25 -0
  201. package/lib/types/dsh-adapter/compat/shell.d.ts.map +1 -0
  202. package/lib/types/dsh-adapter/compat/shell.js +11 -0
  203. package/lib/types/dsh-adapter/contract.d.ts +5 -4
  204. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  205. package/lib/types/dsh-adapter/contract.js +17 -6
  206. package/lib/types/dsh-adapter/ide-channel.d.ts +224 -0
  207. package/lib/types/dsh-adapter/ide-channel.d.ts.map +1 -0
  208. package/lib/types/dsh-adapter/ide-channel.js +556 -0
  209. package/lib/types/dsh-adapter/index.d.ts +18 -3
  210. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  211. package/lib/types/dsh-adapter/index.js +32 -5
  212. package/lib/types/dsh-adapter/plugin.d.ts +4 -1
  213. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  214. package/lib/types/dsh-adapter/plugin.js +197 -49
  215. package/lib/types/dsh-adapter/preset-resolution.d.ts +8 -0
  216. package/lib/types/dsh-adapter/preset-resolution.d.ts.map +1 -1
  217. package/lib/types/dsh-adapter/preset-resolution.js +10 -0
  218. package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts +53 -0
  219. package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts.map +1 -0
  220. package/lib/types/dsh-adapter/session-mount-heartbeat.js +100 -0
  221. package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -1
  222. package/lib/types/dsh-adapter/sessionTree.js +3 -2
  223. package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
  224. package/lib/types/dsh-adapter/settings-sections.js +7 -4
  225. package/lib/types/dsh-adapter/subagents.d.ts +16 -3
  226. package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
  227. package/lib/types/dsh-adapter/subagents.js +92 -29
  228. package/lib/types/dsh-adapter/workspaces.d.ts +46 -3
  229. package/lib/types/dsh-adapter/workspaces.d.ts.map +1 -1
  230. package/lib/types/dsh-adapter/workspaces.js +116 -0
  231. package/lib/types/effortPrefs.d.ts +15 -3
  232. package/lib/types/effortPrefs.d.ts.map +1 -1
  233. package/lib/types/effortPrefs.js +37 -3
  234. package/lib/types/history.d.ts +13 -1
  235. package/lib/types/history.d.ts.map +1 -1
  236. package/lib/types/history.js +15 -2
  237. package/lib/types/homePrefs.d.ts +15 -0
  238. package/lib/types/homePrefs.d.ts.map +1 -0
  239. package/lib/types/homePrefs.js +53 -0
  240. package/lib/types/i18n.d.ts +347 -297
  241. package/lib/types/i18n.d.ts.map +1 -1
  242. package/lib/types/i18n.js +133 -85
  243. package/lib/types/ink/colorize.d.ts +10 -0
  244. package/lib/types/ink/colorize.d.ts.map +1 -1
  245. package/lib/types/ink/colorize.js +21 -0
  246. package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
  247. package/lib/types/ink/components/ScrollBox.js +12 -1
  248. package/lib/types/ink/dom.d.ts +1 -0
  249. package/lib/types/ink/dom.d.ts.map +1 -1
  250. package/lib/types/ink/hooks/use-copy-on-select.d.ts +5 -1
  251. package/lib/types/ink/hooks/use-copy-on-select.d.ts.map +1 -1
  252. package/lib/types/ink/hooks/use-copy-on-select.js +15 -1
  253. package/lib/types/ink/ink.d.ts.map +1 -1
  254. package/lib/types/ink/ink.js +36 -1
  255. package/lib/types/ink/log-update.d.ts.map +1 -1
  256. package/lib/types/ink/log-update.js +19 -1
  257. package/lib/types/ink/output.d.ts +10 -1
  258. package/lib/types/ink/output.d.ts.map +1 -1
  259. package/lib/types/ink/output.js +109 -17
  260. package/lib/types/ink/render-border.d.ts +6 -1
  261. package/lib/types/ink/render-border.d.ts.map +1 -1
  262. package/lib/types/ink/render-border.js +25 -9
  263. package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
  264. package/lib/types/ink/render-node-to-output.js +48 -6
  265. package/lib/types/ink/renderer.d.ts +6 -0
  266. package/lib/types/ink/renderer.d.ts.map +1 -1
  267. package/lib/types/ink/renderer.js +2 -1
  268. package/lib/types/ink/selection.d.ts +88 -0
  269. package/lib/types/ink/selection.d.ts.map +1 -1
  270. package/lib/types/ink/selection.js +164 -0
  271. package/lib/types/ink/sixel-graphics.d.ts +19 -1
  272. package/lib/types/ink/sixel-graphics.d.ts.map +1 -1
  273. package/lib/types/ink/sixel-graphics.js +124 -12
  274. package/lib/types/ink/terminal-image.d.ts +18 -1
  275. package/lib/types/ink/terminal-image.d.ts.map +1 -1
  276. package/lib/types/ink/terminal.d.ts +17 -0
  277. package/lib/types/ink/terminal.d.ts.map +1 -1
  278. package/lib/types/ink/terminal.js +20 -1
  279. package/lib/types/screens/Chat.d.ts +20 -1
  280. package/lib/types/screens/Chat.d.ts.map +1 -1
  281. package/lib/types/screens/Chat.js +296 -76
  282. package/lib/types/screens/SessionSupervisor.d.ts +84 -0
  283. package/lib/types/screens/SessionSupervisor.d.ts.map +1 -0
  284. package/lib/types/screens/SessionSupervisor.js +350 -0
  285. package/lib/types/screens/SessionTree.js +2 -2
  286. package/lib/types/screens/Settings.d.ts.map +1 -1
  287. package/lib/types/screens/Settings.js +32 -9
  288. package/lib/types/screens/StatusLine.d.ts +18 -1
  289. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  290. package/lib/types/screens/StatusLine.js +38 -19
  291. package/lib/types/screens/StatusMetrics.d.ts +79 -22
  292. package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
  293. package/lib/types/screens/StatusMetrics.js +153 -88
  294. package/lib/types/screens/sessionSupervisor/model.d.ts +83 -0
  295. package/lib/types/screens/sessionSupervisor/model.d.ts.map +1 -0
  296. package/lib/types/screens/sessionSupervisor/model.js +69 -0
  297. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts +120 -0
  298. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts.map +1 -0
  299. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.js +593 -0
  300. package/lib/types/sessionMounts.d.ts +272 -0
  301. package/lib/types/sessionMounts.d.ts.map +1 -0
  302. package/lib/types/sessionMounts.js +706 -0
  303. package/lib/types/sessions/format.d.ts.map +1 -1
  304. package/lib/types/sessions/format.js +4 -1
  305. package/lib/types/sessions/resumeFailure.d.ts +38 -0
  306. package/lib/types/sessions/resumeFailure.d.ts.map +1 -0
  307. package/lib/types/sessions/resumeFailure.js +58 -0
  308. package/lib/types/terminal-utils/mermaid.d.ts +44 -0
  309. package/lib/types/terminal-utils/mermaid.d.ts.map +1 -0
  310. package/lib/types/terminal-utils/mermaid.js +83 -0
  311. package/lib/types/tips.d.ts.map +1 -1
  312. package/lib/types/tips.js +175 -19
  313. package/lib/types/tuiDisplayPrefs.d.ts +7 -9
  314. package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
  315. package/lib/types/tuiDisplayPrefs.js +31 -28
  316. package/lib/types/update.d.ts +61 -0
  317. package/lib/types/update.d.ts.map +1 -1
  318. package/lib/types/update.js +194 -0
  319. package/lib/types/utils/fold-long-lines.d.ts +1 -1
  320. package/lib/types/utils/fold-long-lines.js +1 -1
  321. package/lib/types/utils/imageResize.d.ts +90 -0
  322. package/lib/types/utils/imageResize.d.ts.map +1 -0
  323. package/lib/types/utils/imageResize.js +272 -0
  324. package/lib/types/utils/keymap.d.ts +5 -1
  325. package/lib/types/utils/keymap.d.ts.map +1 -1
  326. package/lib/types/utils/keymap.js +23 -0
  327. package/lib/types/working-activity.d.ts +10 -9
  328. package/lib/types/working-activity.d.ts.map +1 -1
  329. package/lib/types/working-activity.js +17 -10
  330. package/lib/types/workspaces.d.ts +2 -1
  331. package/lib/types/workspaces.d.ts.map +1 -1
  332. package/lib/types/workspaces.js +1 -1
  333. package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +10 -10
  334. package/package.json +126 -105
  335. package/presets/liangshen/.dsh-tui-managed.json +1 -1
  336. package/presets/liangshen/agent.cordis.yml +15 -0
  337. package/lib/types/components/design-system/KeyboardShortcutHint.d.ts +0 -19
  338. package/lib/types/components/design-system/KeyboardShortcutHint.d.ts.map +0 -1
  339. package/lib/types/components/design-system/KeyboardShortcutHint.js +0 -14
  340. package/lib/types/dsh-adapter/channel/activity.d.ts +0 -20
  341. package/lib/types/dsh-adapter/channel/activity.d.ts.map +0 -1
  342. package/lib/types/dsh-adapter/channel/activity.js +0 -113
  343. package/lib/types/screens/AgentView.d.ts +0 -23
  344. package/lib/types/screens/AgentView.d.ts.map +0 -1
  345. package/lib/types/screens/AgentView.js +0 -546
  346. package/lib/types/screens/SessionBrowser.d.ts +0 -42
  347. package/lib/types/screens/SessionBrowser.d.ts.map +0 -1
  348. package/lib/types/screens/SessionBrowser.js +0 -911
  349. package/lib/types/terminal-utils/terminal.d.ts +0 -18
  350. package/lib/types/terminal-utils/terminal.d.ts.map +0 -1
  351. package/lib/types/terminal-utils/terminal.js +0 -96
@@ -1,6 +1,7 @@
1
1
  import Schema from '@deepseek-ai/schemastery';
2
2
  import { DEFAULT_STATUS_BAR, normalizePageMargin } from '../tuiDisplayPrefs.js';
3
3
  import { SHORTCUT_ACTIONS } from '../utils/keymap.js';
4
+ import { editableConfig } from './compat/settings.js';
4
5
  export const name = 'dsh-tui';
5
6
  // `tuiWorkspaces` must stay OUT of this code-level inject (issue #183): the
6
7
  // dsh CLI resolves the bundle's cordis.patch.yml from the FIRST copy of this
@@ -12,7 +13,7 @@ export const name = 'dsh-tui';
12
13
  // row-level inject purely as an ordering guarantee when the row exists; when
13
14
  // it does not, plugin.ts/channel.ts fall back to a local workspace runtime.
14
15
  export const inject = ['agents'];
15
- export const Config = Schema.object({
16
+ export const Config = editableConfig(Schema.object({
16
17
  sessionId: Schema.string().required(false),
17
18
  // No schema defaults on the route: a `.default()` here would make an
18
19
  // unset key indistinguishable from an explicit cordis.yml choice and the
@@ -23,6 +24,10 @@ export const Config = Schema.object({
23
24
  cwd: Schema.string().required(false),
24
25
  workspace: Schema.string().required(false),
25
26
  effort: Schema.string().required(false),
27
+ effortDefault: Schema.string().required(false),
28
+ whale: Schema.boolean().default(true),
29
+ whaleIdle: Schema.boolean().default(true),
30
+ minimal: Schema.boolean().default(false),
26
31
  activity: Schema.boolean().default(true),
27
32
  activityFrames: Schema.string().required(false),
28
33
  contextBar: Schema.boolean().default(true),
@@ -42,6 +47,7 @@ export const Config = Schema.object({
42
47
  promptSessionLabel: Schema.boolean().default(false),
43
48
  expandEditor: Schema.boolean().default(true),
44
49
  smoothStreaming: Schema.boolean().default(true),
50
+ mermaidDiagrams: Schema.boolean().default(true),
45
51
  statusBar: Schema.object({
46
52
  compact: Schema.boolean().default(DEFAULT_STATUS_BAR.compact),
47
53
  model: Schema.boolean().default(DEFAULT_STATUS_BAR.model),
@@ -72,13 +78,18 @@ export const Config = Schema.object({
72
78
  approval: Schema.union(['ask', 'never']).required(false),
73
79
  permission: Schema.string().required(false),
74
80
  })).required(false),
75
- });
81
+ }), [
82
+ 'diffLayout', 'thinkingFold', 'toolBackground', 'scrollGutter', 'pageMargin',
83
+ 'foldTerminalCommand', 'promptSessionLabel', 'expandEditor', 'smoothStreaming',
84
+ 'mermaidDiagrams', 'effortDefault', 'statusBar', 'whale', 'whaleIdle', 'minimal',
85
+ 'lang', 'fullscreen', 'terminalImages', 'shortcuts',
86
+ ]);
76
87
  /**
77
88
  * Start the interactive TUI front door, delegating to the JSX implementation
78
89
  * in `./plugin.tsx` (see its module doc for the full contract).
79
90
  * @param ctx - the plugin context.
80
91
  * @param config - the validated dsh-tui configuration.
81
- * @returns a promise settling when the TUI teardown completes.
92
+ * @returns a promise settling when the Loader entry has scheduled its runtime.
82
93
  */
83
94
  export async function apply(ctx, config) {
84
95
  // Upstream drift is NO LONGER spammed to stderr here: per-package
@@ -87,6 +98,22 @@ export async function apply(ctx, config) {
87
98
  // natural-language notice now renders in the logo header under the
88
99
  // startup tip (LogoV2 ← upstreamDriftSummary); CI keeps the hard gate
89
100
  // via scripts/verify-upstream-contract.ts.
90
- const { apply: tuiApply } = await import('./plugin.js');
91
- return tuiApply(ctx, config);
101
+ const { apply: tuiApply, handleStartupError } = await import('./plugin.js');
102
+ let disposed = false;
103
+ ctx.effect(() => () => { disposed = true; });
104
+ // Registry diagnostics can await the whole Loader. Do not make this Host
105
+ // row await the runtime in return. Let Host providers settle before starting
106
+ // a Cordis-owned child; the original row still owns volatile Config.
107
+ const loader = ctx.get('loader');
108
+ void (loader?.await() ?? ctx.fiber.await()).then(() => {
109
+ if (disposed)
110
+ return;
111
+ return ctx.plugin({
112
+ name: 'dsh-tui-runtime',
113
+ apply: (runtimeCtx) => tuiApply(runtimeCtx, config, ctx),
114
+ });
115
+ }).catch(error => {
116
+ if (!disposed)
117
+ handleStartupError(ctx, error);
118
+ });
92
119
  }
@@ -1,6 +1,7 @@
1
1
  import type { Agent } from '@deepseek-ai/dsh-agent';
2
2
  import type { Context } from '@deepseek-ai/cordis';
3
3
  import { Config } from './index.js';
4
+ import { type RuntimeConfig } from './compat/settings.js';
4
5
  import { render } from '../ui.js';
5
6
  /**
6
7
  * Extract the startup prompt from raw app argv. `--resume <session>` selects
@@ -22,7 +23,7 @@ export declare function initialPromptFromCmdlineArgs(args: readonly string[] | u
22
23
  */
23
24
  export type TuiHostMode = 'interactive' | 'invalid-explicit-launch' | 'headless-host';
24
25
  export declare function resolveTuiHostMode(stdoutIsTTY?: boolean, env?: NodeJS.ProcessEnv): TuiHostMode;
25
- export declare function apply(ctx: Context, config: Config): Promise<void>;
26
+ export declare function apply(ctx: Context, runtimeConfig: RuntimeConfig<Config>, configOwner?: Context): Promise<void>;
26
27
  /**
27
28
  * Distinguish a user-driven exit from a cordis context teardown (issue #12).
28
29
  *
@@ -64,4 +65,6 @@ export declare function isExitResumable(deps: {
64
65
  * Exported for scripts/verify-shutdown-fallback.
65
66
  */
66
67
  export declare function finishExit(ctx: Context, instance: Awaited<ReturnType<typeof render>> | undefined, fullscreen: boolean, notice: string | undefined, stderrNotice: string | undefined, done: () => void): Promise<void>;
68
+ /** Deferred runtime failures must restore the terminal and fail the process. */
69
+ export declare function handleStartupError(ctx: Context, error: unknown): void;
67
70
  //# sourceMappingURL=plugin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,wBAAwB,CAAA;AAGhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAmDnC,OAAO,EAAE,MAAM,EAAkC,MAAM,UAAU,CAAA;AAgCjE;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,CAcxF;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,yBAAyB,GAAG,eAAe,CAAA;AAErF,wBAAgB,kBAAkB,CAChC,WAAW,UAAgC,EAC3C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,WAAW,CASb;AAED,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgiDvE;AAoID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GAAG;IACjF,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB,CAcA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,KAAK,GAAG,SAAS,CAAA;IAC5B,YAAY,EAAE,KAAK,CAAA;CACpB,GAAG,OAAO,CAQV;AAgBD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,GAAG,SAAS,EACxD,UAAU,EAAE,OAAO,EACnB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,IAAI,EAAE,MAAM,IAAI,GACf,OAAO,CAAC,IAAI,CAAC,CAmFf"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,wBAAwB,CAAA;AAGhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACnC,OAAO,EAA+D,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAwDtH,OAAO,EAAE,MAAM,EAAkC,MAAM,UAAU,CAAA;AAgCjE;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,CAcxF;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,yBAAyB,GAAG,eAAe,CAAA;AAErF,wBAAgB,kBAAkB,CAChC,WAAW,UAAgC,EAC3C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,WAAW,CASb;AAED,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,WAAW,GAAE,OAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAgnDzH;AAmMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GAAG;IACjF,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB,CAcA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,KAAK,GAAG,SAAS,CAAA;IAC5B,YAAY,EAAE,KAAK,CAAA;CACpB,GAAG,OAAO,CAQV;AAgBD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,GAAG,SAAS,EACxD,UAAU,EAAE,OAAO,EACnB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,IAAI,EAAE,MAAM,IAAI,GACf,OAAO,CAAC,IAAI,CAAC,CAmFf;AA4HD,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAIrE"}
@@ -4,6 +4,8 @@ import { SessionId } from '@deepseek-ai/dsh-session';
4
4
  import UserQuestionService from '@deepseek-ai/dsh-user-questions';
5
5
  import * as toolAskUser from '@deepseek-ai/dsh-tool-ask-user';
6
6
  import Schema from '@deepseek-ai/schemastery';
7
+ import { Config } from './index.js';
8
+ import { configValues, createSettingsScope, resolveSettingsNamespace } from './compat/settings.js';
7
9
  import { createChannel } from './channel.js';
8
10
  import { createChannelSceneOutlet } from './channel-scene-outlet.js';
9
11
  import { mountChannelUi } from './channel-ui.js';
@@ -26,19 +28,24 @@ import { migratePresetPref, readPresetPref } from '../presetPrefs.js';
26
28
  import { readEffortPref } from '../effortPrefs.js';
27
29
  import { composePreset, filterMinimalPresetTools, resolvePersistedPreset, resolvePersistedRoute, runningPresetOf } from './presets.js';
28
30
  import { ensurePackagedPresets } from './packaged-presets.js';
31
+ import { registerBundledPresets } from './bundled-presets.js';
29
32
  import { ensureLegacySessionEventTypes, snapshotLiveSessionEvents } from './compat/index.js';
30
33
  import { clearResumeTarget, resumeTargetFromArgv, writeResumeTarget } from '../sessionHistory.js';
34
+ import { readHomePrefs } from '../homePrefs.js';
31
35
  import { resolveSessionCwd } from '../utils/workspaceRoot.js';
32
36
  import { beginRestartAttempt, checkForTuiUpdate, installedTuiVersion, isBootDeadlockTarget, isStandaloneRuntime, isVersionNewer, logRestartEvent, resolveDshProfileName, resolveTuiUpdateTarget, restartTui, updateTuiAndRestart, writeHandoffNotice } from '../update.js';
33
37
  import { getLang, isLang, resolveStartupLang, setLang, t, writeLangPref } from '../i18n.js';
34
- import { DEFAULT_PAGE_MARGIN, DEFAULT_STATUS_BAR, applyPageMargin, isPageMarginMode, normalizePageMargin, normalizeScrollGutter, normalizeStatusBar, normalizeToolBackground, parsePageMarginSpec } from '../tuiDisplayPrefs.js';
38
+ import { DEFAULT_PAGE_MARGIN, DEFAULT_STATUS_BAR, applyMermaidDiagrams, applyPageMargin, isPageMarginMode, normalizePageMargin, normalizeScrollGutter, normalizeStatusBar, normalizeToolBackground, parsePageMarginSpec } from '../tuiDisplayPrefs.js';
35
39
  import { draftComboConflicts, effectiveComboString, parseComboDraft, setKeymapOverrides, SHORTCUT_ACTIONS, } from '../utils/keymap.js';
36
40
  import { attachHerdrIntegration } from '../herdr.js';
37
41
  import { logMouseDebug } from '../utils/debug.js';
38
42
  import { Chat } from '../screens/Chat.js';
39
43
  import { openInjectChannel } from './inject-channel.js';
44
+ import { startSessionMountHeartbeat } from './session-mount-heartbeat.js';
45
+ import { reserveMount } from '../sessionMounts.js';
40
46
  import { getHostDialogStore } from './dialogs.js';
41
47
  import { getHostStatusStore } from './status.js';
48
+ import { createActivityStore } from './activity-store.js';
42
49
  import { getHostToastStore } from './toast.js';
43
50
  import { getHostShortcuts } from './shortcuts.js';
44
51
  import { getHostThemes } from './themes.js';
@@ -106,7 +113,8 @@ export function resolveTuiHostMode(stdoutIsTTY = process.stdout.isTTY === true,
106
113
  const explicitTuiLaunch = env.DSH_TUI_LAUNCHER_VERSION !== undefined || isStandaloneRuntime();
107
114
  return explicitTuiLaunch ? 'invalid-explicit-launch' : 'headless-host';
108
115
  }
109
- export async function apply(ctx, config) {
116
+ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
117
+ const config = configValues(runtimeConfig);
110
118
  // /restart handoff diagnosis: the replacement process is marked by env and
111
119
  // logs its boot progress to ~/.dsh-tui/restart.log (ordinary launches stay
112
120
  // silent). First line lands before anything in this function can throw.
@@ -178,22 +186,23 @@ export async function apply(ctx, config) {
178
186
  ctx.logger.info('dsh-tui: non-interactive host detected (stdout is not a TTY); skipping the TUI frontend');
179
187
  return;
180
188
  }
181
- // The official profile launcher owns the system preset root and replaces
182
- // any bundle-supplied roots at boot. Install dsh-tui's bundled presets via
183
- // the roster's supported user-root seam before resolving the first agent.
184
- // Never overwrite an existing directory unless it carries our marker.
185
- try {
186
- for (const result of ensurePackagedPresets()) {
187
- if (result.status === 'conflict') {
188
- ctx.logger.warn(`dsh-tui: packaged preset "${result.id}" was not installed because an unmanaged preset already uses that id`);
189
+ // Validate settings before creating an agent or taking over the terminal.
190
+ const tuiSettingsNs = resolveSettingsNamespace(configOwner, Config);
191
+ // Modern hosts own a declarative registry; old hosts discover directories.
192
+ // A modern bundle failure must not silently fall back to obsolete files.
193
+ if (!await registerBundledPresets(ctx))
194
+ try {
195
+ for (const result of ensurePackagedPresets()) {
196
+ if (result.status === 'conflict') {
197
+ ctx.logger.warn(`dsh-tui: packaged preset "${result.id}" was not installed because an unmanaged preset already uses that id`);
198
+ }
189
199
  }
190
200
  }
191
- }
192
- catch (error) {
193
- // A read-only home must not make the whole terminal unusable; the other
194
- // official and user presets remain available.
195
- ctx.logger.warn(`dsh-tui: unable to install packaged presets (${error instanceof Error ? error.message : String(error)})`);
196
- }
201
+ catch (error) {
202
+ // A read-only home must not make the whole terminal unusable; the other
203
+ // official and user presets remain available.
204
+ ctx.logger.warn(`dsh-tui: unable to install packaged presets (${error instanceof Error ? error.message : String(error)})`);
205
+ }
197
206
  // UI language resolution: DSH_TUI_LANG env var wins, then the
198
207
  // settings.yaml `dsh-tui.lang` user layer (applied once the settings
199
208
  // namespace registers below), then cordis.yml `lang`, then the
@@ -398,6 +407,14 @@ export async function apply(ctx, config) {
398
407
  // Opening a persisted TUI session is an explicit ownership action too.
399
408
  // Older TUI versions only wrote the Session log, so attaching on every
400
409
  // startup repairs those durable-but-ungrouped sessions idempotently.
410
+ //
411
+ // This is ALSO how a workspace enters the rail: `resolveByPath(cwd) ??
412
+ // create(cwd)` mints the durable record for the directory this terminal
413
+ // was launched in, so the session screen lists every directory a TUI has
414
+ // ever started in. The ledger is DSH's own workspace store, so the Web UI
415
+ // reads the same records. There is deliberately no rail-side "add a
416
+ // workspace" control any more: a terminal's launch directory is the whole
417
+ // registration story.
401
418
  const attached = await attachSessionToWorkspace(ctx, meta.cwd, agent.session.id);
402
419
  if (!attached) {
403
420
  ctx.logger.warn(`dsh-tui: session "${agent.session.id}" has no workspace ownership because workspaceRegistry is not mounted`);
@@ -413,8 +430,23 @@ export async function apply(ctx, config) {
413
430
  // validated startup resolution, on resume the route the target session's
414
431
  // own records carry (a complete cordis.yml pin wins over them).
415
432
  const displayRoute = createdRoute ?? startupRoute;
433
+ // Read side of the activity projection: filled by the working-activity
434
+ // plugin's unit, read by the status line. Created BEFORE the channel on
435
+ // purpose — `createChannel` binds its agent synchronously while it is still
436
+ // being constructed, and that bind seeds this store (see `seedActivity`
437
+ // below), so a store declared after the channel is still in its temporal
438
+ // dead zone when the first seed arrives and takes the whole boot down with
439
+ // it. One store per process; a composition without the projection service
440
+ // simply leaves it empty. `activity: false` is a static config-time switch
441
+ // (the runtime `/activity` command only changes the preset), so a hidden
442
+ // line attaches nothing at all — no feed, no 500ms tick.
443
+ const activityStore = createActivityStore(ctx, config.activity !== false);
416
444
  const rawChannel = createChannel(ctx, agent, {
417
445
  model: displayRoute.model,
446
+ // The activity projection only pushes on change; read the current value as
447
+ // soon as this session binds so a resumed or reattached session renders its
448
+ // line immediately instead of waiting for the next event.
449
+ seedActivity: session => activityStore.seed(session),
418
450
  // A RESUMED session keeps its persisted header cwd (issue #96 review):
419
451
  // pre-upgrade sessions recorded the launch directory, and re-resolving
420
452
  // from the current launch directory would split @ expansion / file
@@ -488,8 +520,11 @@ export async function apply(ctx, config) {
488
520
  // Root page-margin store: the PageMargin inset box sits ABOVE Chat, so
489
521
  // the channel version bump (which re-renders everything below Chat)
490
522
  // cannot drive it. Seed the store from config before the tree mounts;
491
- // applyDisplay below mirrors every settings change into it live.
523
+ // applyDisplay below mirrors every settings change into it live. The
524
+ // mermaid switch rides the same kind of store (Markdown is memoized by
525
+ // content, so no prop reaches the diagram component).
492
526
  applyPageMargin(config.pageMargin);
527
+ applyMermaidDiagrams(config.mermaidDiagrams);
493
528
  // Plugin toasts ride the channel's own notification surface: the runtime
494
529
  // already sanitized/rate-limited the delivery, the sink only forwards.
495
530
  // Without the extensions row (tuiToast absent) plugin toasts are dropped
@@ -527,18 +562,11 @@ export async function apply(ctx, config) {
527
562
  resolveSettingsReady = () => resolve();
528
563
  setTimeout(resolve, 300);
529
564
  });
530
- // Register the dsh-tui settings namespace so the /settings screen can
531
- // edit it (the section below was '命名空间未注册' without this): the
532
- // user layer in settings.yaml wins over cordis.yml's diffLayout, and
533
- // watch() lands commits on the live channel — no recompose needed.
565
+ // Old hosts register a settings.yaml scope. 0.1.7 projects the plugin's
566
+ // volatile Config fields instead; both paths apply edits without remounting.
534
567
  ctx.inject(['settings'], (settingsCtx) => {
535
- // alpha.2 removed the `settingsNamespace()` brand helper: register() now
536
- // takes the raw string and validates it itself, while rc.2 still wants the
537
- // branded handle. Brands are type-only, so the constant cast compiles
538
- // against both lines and the runtime value is identical ('dsh-tui' always
539
- // satisfied the namespace pattern).
540
- const tuiSettingsNs = 'dsh-tui';
541
- const scope = settingsCtx.settings.register(tuiSettingsNs, Schema.object({
568
+ // Loader targets the Config owner's fiber, not the injected child fiber.
569
+ const scope = createSettingsScope(configOwner, settingsCtx.settings, tuiSettingsNs, Schema.object({
542
570
  diffLayout: Schema.union(['auto', 'split', 'unified']).default('auto'),
543
571
  thinkingFold: Schema.union(['preview', 'full']).default('preview'),
544
572
  toolBackground: Schema.union(['none', 'subtle', 'strong']).default('none'),
@@ -561,6 +589,8 @@ export async function apply(ctx, config) {
561
589
  expandEditor: Schema.boolean(),
562
590
  // Same no-default rule: applyDisplay resolves `?? config.smoothStreaming ?? true`.
563
591
  smoothStreaming: Schema.boolean(),
592
+ // Same no-default rule: applyDisplay resolves `?? config.mermaidDiagrams ?? true`.
593
+ mermaidDiagrams: Schema.boolean(),
564
594
  // No default on purpose: unset keeps the boot chain decisive
565
595
  // (applyEffortDefault hands `undefined` to channel.setDefaultEffort,
566
596
  // which resolves cordis.yml `effort` → effort.json → adapter default).
@@ -606,7 +636,10 @@ export async function apply(ctx, config) {
606
636
  // action (see the keymap utility). Unset keeps the default binding
607
637
  // and the section's format() shows the effective combos.
608
638
  shortcuts: Schema.object(Object.fromEntries(SHORTCUT_ACTIONS.map(action => [action.id, Schema.string().required(false)]))).required(false),
609
- }));
639
+ }), () => {
640
+ const current = configValues(runtimeConfig);
641
+ return { ...current, lang: isLang(current.lang) ? current.lang : undefined };
642
+ });
610
643
  const applyLayout = (value) => {
611
644
  if (!shadow)
612
645
  channel.setDiffLayout(value.diffLayout ?? config.diffLayout ?? 'auto');
@@ -663,15 +696,15 @@ export async function apply(ctx, config) {
663
696
  channel.setPromptSessionLabel(value.promptSessionLabel ?? config.promptSessionLabel ?? false);
664
697
  channel.setExpandEditor(value.expandEditor ?? config.expandEditor ?? true);
665
698
  channel.setSmoothStreaming(value.smoothStreaming ?? config.smoothStreaming ?? true);
699
+ applyMermaidDiagrams(value.mermaidDiagrams ?? config.mermaidDiagrams);
666
700
  channel.setStatusBar(normalizeStatusBar(value.statusBar ?? config.statusBar));
667
701
  };
668
- // Shortcut overrides resolve per action: settings user layer wins over
669
- // cordis.yml's `shortcuts` (same precedence as every other field);
670
- // unset everywhere keeps the registry default. Applied live into the
671
- // keymap module — the very next keypress matches the new combos.
702
+ // Legacy user scopes layer over cordis.yml. Modern Config is already
703
+ // resolved: an unset action must not revive its startup override.
704
+ // Applied live so the very next keypress matches the new combos.
672
705
  const applyShortcuts = (value) => {
673
706
  const userLayer = value.shortcuts ?? {};
674
- const configLayer = config.shortcuts ?? {};
707
+ const configLayer = scope.legacy ? config.shortcuts ?? {} : {};
675
708
  const merged = {};
676
709
  for (const action of SHORTCUT_ACTIONS) {
677
710
  const user = userLayer[action.id];
@@ -720,7 +753,11 @@ export async function apply(ctx, config) {
720
753
  // not an explicit undefined), and the later watch commit (fullscreen
721
754
  // back to undefined) leaves the fullscreen decision unchanged.
722
755
  const bootSettings = scope.get();
723
- const fullscreenMigration = planFullscreenFactoryMigration(bootSettings.fullscreen, readAppliedMigrations());
756
+ // The old migration applies only to the separate user layer. A modern
757
+ // profile's explicit inline Config must never be mistaken for that layer.
758
+ const fullscreenMigration = scope.legacy
759
+ ? planFullscreenFactoryMigration(bootSettings.fullscreen, readAppliedMigrations())
760
+ : 'done';
724
761
  void commitFullscreenFactoryMigration(fullscreenMigration, {
725
762
  unset: () => settingsCtx.settings.mutate(tuiSettingsNs, [{ op: 'unset', path: ['fullscreen'] }]),
726
763
  });
@@ -730,7 +767,7 @@ export async function apply(ctx, config) {
730
767
  const { fullscreen: staleFullscreen, ...migratedSettings } = bootSettings;
731
768
  apply(fullscreenMigration === 'unset' ? migratedSettings : bootSettings);
732
769
  let lastTerminalImages = bootSettings.terminalImages ?? config.terminalImages ?? true;
733
- scope.watch(next => {
770
+ settingsCtx.effect(() => scope.watch(next => {
734
771
  apply(next);
735
772
  if (typeof next.fullscreen === 'boolean' && next.fullscreen !== bootedFullscreen) {
736
773
  notifyChannel(t('settings-fullscreen-restart'), { color: 'warning' });
@@ -740,7 +777,7 @@ export async function apply(ctx, config) {
740
777
  channel.notify(t('settings-terminal-images-restart'), { color: 'warning' });
741
778
  }
742
779
  lastTerminalImages = terminalImages;
743
- });
780
+ }));
744
781
  resolveSettingsReady?.();
745
782
  });
746
783
  // The /settings screen's own section: the dsh-tui namespace comes from
@@ -813,6 +850,12 @@ export async function apply(ctx, config) {
813
850
  hintEn: d => `Fold/unfold the goal/todo panel. Default: ${d}.`,
814
851
  hintZh: d => `折叠/展开目标与待办面板。默认 ${d}。`,
815
852
  },
853
+ questionFold: {
854
+ label: 'Question panel fold shortcut',
855
+ zh: '提问面板折叠快捷键',
856
+ hintEn: d => `Fold/unfold the pending question panel. Default: ${d}.`,
857
+ hintZh: d => `折叠/展开等待回答的提问面板。默认 ${d}。`,
858
+ },
816
859
  expandEditor: {
817
860
  label: 'Fullscreen editor shortcut',
818
861
  zh: '全屏草稿编辑快捷键',
@@ -855,7 +898,7 @@ export async function apply(ctx, config) {
855
898
  {
856
899
  const settingsSections = getHostSettingsSections(ctx.get('tuiSettingsSections')) ?? getLocalSettingsSectionsHost(ctx);
857
900
  const unregister = settingsSections.register({
858
- ns: 'dsh-tui',
901
+ ns: tuiSettingsNs,
859
902
  title: 'dsh-tui',
860
903
  groups: [
861
904
  { id: 'status-bar', title: 'Status bar', descriptions: { zh: '底栏设置' } },
@@ -1038,6 +1081,18 @@ export async function apply(ctx, config) {
1038
1081
  return String(typeof value === 'boolean' ? value : config.smoothStreaming !== false);
1039
1082
  },
1040
1083
  },
1084
+ {
1085
+ path: ['mermaidDiagrams'],
1086
+ label: 'Mermaid diagrams',
1087
+ descriptions: { zh: 'Mermaid 图表' },
1088
+ hint: 'Render ```mermaid fences in replies as box-drawing diagrams (flowchart, sequence, state, class, ER, pie, mindmap, timeline, gitGraph). Diagrams wider than the terminal, or of an unsupported type, keep the fenced source. Applies immediately. On by default.',
1089
+ hintDescriptions: { zh: '把回复中的 ```mermaid 代码块画成字符图(flowchart、sequence、state、class、ER、pie、mindmap、timeline、gitGraph)。比终端宽或类型不支持的图保留源码。立即生效。默认开启。' },
1090
+ kind: 'boolean',
1091
+ format(value) {
1092
+ // Unset in settings.yaml: the effective default is on.
1093
+ return String(typeof value === 'boolean' ? value : config.mermaidDiagrams !== false);
1094
+ },
1095
+ },
1041
1096
  {
1042
1097
  path: ['recapOnOpen'],
1043
1098
  label: 'Auto recap on open',
@@ -1429,17 +1484,37 @@ export async function apply(ctx, config) {
1429
1484
  // BEFORE creating Chat: the element must see the same bootedFullscreen the
1430
1485
  // root tree resolves after settingsReady below.
1431
1486
  await settingsReady;
1487
+ /**
1488
+ * One-shot workspace-home landing.
1489
+ *
1490
+ * Only an ORDINARY launch is eligible: an explicit resume (`--resume` /
1491
+ * `-c` / the launcher's remembered target), an explicit workspace target, and
1492
+ * a first prompt all mean the user already said where they want to be, and
1493
+ * covering that with a browser would be the TUI second-guessing them. The
1494
+ * `seen` marker is written when the screen is dismissed (see `closeHome`),
1495
+ * so a process that dies before the first frame does not consume it.
1496
+ */
1497
+ const homeSeen = readHomePrefs().seen === true;
1498
+ const openHomeOnBoot = !homeSeen
1499
+ && launchSessionId === undefined
1500
+ && requestedWorkspace === undefined
1501
+ && initialPromptFromCmdlineArgs(process.argv.slice(2)) === '';
1432
1502
  const chat = React.createElement(Chat, {
1433
1503
  channel,
1434
1504
  renderScene: createChannelSceneOutlet(() => rawChannel.pluginScene),
1435
1505
  questionStore,
1436
1506
  approvalStore,
1437
1507
  injectControllerRef,
1508
+ openHomeOnBoot,
1438
1509
  // The dsh-tui-extensions row's services (managed dialogs, status line,
1439
1510
  // shortcuts). Soft-consumed: absent the row (stale patch, bare embed),
1440
1511
  // Chat falls back to inert stores and no shortcut registry.
1441
1512
  extensionDialogs: getHostDialogStore(ctx.get('tuiDialogs')),
1442
1513
  extensionStatus: getHostStatusStore(ctx.get('tuiStatus')),
1514
+ // The working line's semantics belong to the dsh-working-activity plugin's
1515
+ // session projection; this store is the read side of that seam, so the TUI
1516
+ // no longer runs a second activity tracker of its own.
1517
+ activityStore,
1443
1518
  extensionShortcuts: getHostShortcuts(ctx.get('tuiShortcuts')),
1444
1519
  themeHost,
1445
1520
  // Full-screen surfaces inside Chat — the trajectory scene and the session
@@ -1555,6 +1630,15 @@ export async function apply(ctx, config) {
1555
1630
  if (injectChannel) {
1556
1631
  ctx.effect(() => () => injectChannel.close());
1557
1632
  }
1633
+ // Cross-process session mounting: publish the sessions this process has
1634
+ // mounted so another TUI (a different terminal process on the same machine)
1635
+ // can see them as occupied and refuse to mount the same log. Two processes
1636
+ // driving one session would interleave writes into a single append-only
1637
+ // transcript, so this is the guard that makes multi-process TUI use safe.
1638
+ // Registered on the same teardown funnel as everything else: the disposer
1639
+ // stops the heartbeat and removes the claim, so a clean exit frees its
1640
+ // sessions at once while a killed process is reclaimed by liveness.
1641
+ ctx.effect(() => startSessionMountHeartbeat(ctx));
1558
1642
  // Check in the background so registry latency never delays the first frame.
1559
1643
  // A failed/offline check is intentionally silent; the manual `/update`
1560
1644
  // command remains available regardless of network access.
@@ -1627,6 +1711,40 @@ async function resolveAgent(ctx, requestedSessionId, configuredRoute, startupRou
1627
1711
  if (existing !== undefined) {
1628
1712
  return { agent: existing, agentPreset: runningPresetOf(existing.session) };
1629
1713
  }
1714
+ // The launch-time counterpart of the in-session `/resume` claim
1715
+ // (`channel/session-resume.ts`), and it has to happen before ANY await:
1716
+ // without it `dsh-tui --resume <id>` mounts the log purely because the user
1717
+ // asked for it, so a second terminal doing the same joins the first and
1718
+ // both interleave writes into one append-only transcript. The mount
1719
+ // publisher cannot cover this — it publishes the set, it never refuses a
1720
+ // mount — so the claim is the only place the refusal can come from.
1721
+ //
1722
+ // Every failure refuses. "The ledger was busy" and "the ledger could not be
1723
+ // read" are not evidence that the session is free, and a boot that guesses
1724
+ // the wrong way here interleaves two writers into one append-only log —
1725
+ // the one outcome nothing downstream can repair. A genuinely read-only home
1726
+ // therefore costs a `--resume` refusal, which is loud and fixable, instead
1727
+ // of silent corruption.
1728
+ const reserved = await reserveMount(requestedSessionId);
1729
+ if (!reserved.ok) {
1730
+ if (reserved.reason === 'occupied') {
1731
+ throw new Error(`dsh-tui: cannot resume session "${requestedSessionId}": it is mounted by another TUI terminal ` +
1732
+ `(pid ${reserved.holders[0] ?? 0}) — two processes driving one session log would corrupt it. ` +
1733
+ 'Close that terminal, or drop --resume to start a fresh session.');
1734
+ }
1735
+ if (reserved.reason === 'busy') {
1736
+ throw new Error(`dsh-tui: cannot resume session "${requestedSessionId}": another process is holding the ` +
1737
+ 'session mount ledger right now, so its occupancy could not be checked. Retry in a moment.');
1738
+ }
1739
+ throw new Error(`dsh-tui: cannot resume session "${requestedSessionId}": its occupancy could not be verified ` +
1740
+ `(${reserved.detail}). Refusing rather than risk two processes writing one session log. ` +
1741
+ 'If that file is damaged, remove it (and the matching .lock) while no other TUI is running, ' +
1742
+ 'or drop --resume to start a fresh session.');
1743
+ }
1744
+ // The reservation spans the awaits below: the agent only appears in the
1745
+ // registry once `agents.resume` returns, and a publisher beat landing in
1746
+ // between would otherwise drop the claim this boot just committed.
1747
+ const reservation = reserved.reservation;
1630
1748
  try {
1631
1749
  // Compat boundary: register vouched-for legacy event types before the
1632
1750
  // strict read path (issue #153) — same seam as the /resume picker,
@@ -1659,6 +1777,9 @@ async function resolveAgent(ctx, requestedSessionId, configuredRoute, startupRou
1659
1777
  };
1660
1778
  }
1661
1779
  catch (error) {
1780
+ // A claim says "this process is driving the log". A resume that never
1781
+ // mounted must not leave one behind for a peer to see and refuse.
1782
+ reservation.abandon();
1662
1783
  // A launch-time --resume is an explicit request: silently substituting a
1663
1784
  // fresh session presents a cold conversation as the resumed one (the
1664
1785
  // "resume did nothing" failure mode — the warn below never reached a
@@ -1669,6 +1790,11 @@ async function resolveAgent(ctx, requestedSessionId, configuredRoute, startupRou
1669
1790
  'the stored log is unreadable or corrupt; no fresh session was started instead. ' +
1670
1791
  'Drop --resume to start fresh, or repair the session log first.', { cause: error });
1671
1792
  }
1793
+ finally {
1794
+ // The reservation only has to outlive the mount. From here the agent is
1795
+ // in the registry, which is what the publisher derives the set from.
1796
+ reservation.settle();
1797
+ }
1672
1798
  }
1673
1799
  const sessionId = SessionId(randomUUID());
1674
1800
  const presetPref = configuredPreset === undefined ? readPresetPref() : undefined;
@@ -1686,21 +1812,38 @@ async function resolveAgent(ctx, requestedSessionId, configuredRoute, startupRou
1686
1812
  if (rejected !== undefined) {
1687
1813
  ctx.logger.warn(`dsh-tui: model route ${rejected.provider}/${rejected.model} is not advertised by provider "${rejected.provider}"; falling back to ${route.provider}/${route.model}`);
1688
1814
  }
1689
- const created = await ctx.agents.create({
1690
- sessionId,
1691
- meta: {
1692
- ...meta,
1693
- // Durable header value: a later resume re-mounts exactly this preset.
1694
- ...(composed.agentPreset === undefined ? {} : { agentPreset: composed.agentPreset }),
1695
- },
1696
- agentOptions: route,
1697
- ...(composed.setup === undefined ? {} : { setup: composed.setup }),
1698
- }).catch((error) => {
1815
+ // Reserve the fresh id before the factory, exactly like the in-session
1816
+ // creates: from the moment `agents.create` returns this process holds the
1817
+ // only write handle on a log the publisher has not named yet. A brand-new id
1818
+ // cannot conflict, so a refusal is only warned about — it costs
1819
+ // announcement, not correctness — but the reservation is what keeps the gap
1820
+ // between the create and the next beat from being open.
1821
+ const bootReserved = await reserveMount(String(sessionId));
1822
+ if (!bootReserved.ok && bootReserved.reason !== 'occupied') {
1823
+ ctx.logger.warn(`dsh-tui: could not announce the new session in the mount ledger: ${bootReserved.reason}`);
1824
+ }
1825
+ const bootReservation = bootReserved.ok ? bootReserved.reservation : undefined;
1826
+ let created;
1827
+ try {
1828
+ created = await ctx.agents.create({
1829
+ sessionId,
1830
+ meta: {
1831
+ ...meta,
1832
+ // Durable header value: a later resume re-mounts exactly this preset.
1833
+ ...(composed.agentPreset === undefined ? {} : { agentPreset: composed.agentPreset }),
1834
+ },
1835
+ agentOptions: route,
1836
+ ...(composed.setup === undefined ? {} : { setup: composed.setup }),
1837
+ });
1838
+ }
1839
+ catch (error) {
1840
+ bootReservation?.abandon();
1699
1841
  // Fail loud with the reason on stderr — a dead TUI with no message is
1700
1842
  // the worst outcome for a misconfigured leaf (unknown provider/model).
1701
1843
  const message = error instanceof Error ? error.message : String(error);
1702
1844
  throw new Error(`dsh-tui: failed to create agent (provider=${route.provider}, model=${route.model}): ${message}`, { cause: error });
1703
- });
1845
+ }
1846
+ bootReservation?.settle();
1704
1847
  return { agent: created.agent, handle: created, agentPreset: composed.agentPreset, route };
1705
1848
  }
1706
1849
  /**
@@ -1947,6 +2090,11 @@ function runUpdate(ctx, profile, sessionId, targetVersion) {
1947
2090
  });
1948
2091
  });
1949
2092
  }
2093
+ /** Deferred runtime failures must restore the terminal and fail the process. */
2094
+ export function handleStartupError(ctx, error) {
2095
+ const message = error instanceof Error ? error.message : String(error);
2096
+ void finishExit(ctx, undefined, lastBootedFullscreen ?? true, undefined, `dsh-tui startup failed: ${message}`, () => disposeRootAndExit(ctx, 1));
2097
+ }
1950
2098
  /**
1951
2099
  * Dispose the whole application before process exit, with a bounded fallback.
1952
2100
  * Mirrors the deleted dsh-tui front-door exit semantics.
@@ -46,4 +46,12 @@ export declare function resolveRecordedPreset(session: {
46
46
  * a broken exact preset can never be mistaken for an unknown id.
47
47
  */
48
48
  export declare function resolveCompatiblePreset(presets: AgentPresetsLike, requested?: string): Promise<AgentPresetInfo>;
49
+ /**
50
+ * The i18n dictionary id a roster preset's localized display text resolves
51
+ * under. The 0.1.2 line renamed the official PTC preset `code` → `ptc`, but
52
+ * the dictionary keys still use the legacy `code` id (`preset-name-code` /
53
+ * `preset-desc-code`), so the `/preset` picker's display lookup must bridge
54
+ * the roster id back. User-authored ids pass through untouched.
55
+ */
56
+ export declare function presetDisplayId(id: string): string;
49
57
  //# sourceMappingURL=preset-resolution.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"preset-resolution.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/preset-resolution.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAAA;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,+DAA+D;AAC/D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,IAAI,IAAI,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC,CAAA;IAC3C,OAAO,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAC9C,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAC/D,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAClE,yEAAyE;IACzE,UAAU,CAAC,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,OAAO,CAAA;KAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAC3D;AAED,2EAA2E;AAC3E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAEnE;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE;IAC7C,MAAM,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAChC,MAAM,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;CACnD,GAAG,MAAM,GAAG,SAAS,CASrB;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,gBAAgB,EACzB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,CAAC,CAQ1B"}
1
+ {"version":3,"file":"preset-resolution.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/preset-resolution.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAAA;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,+DAA+D;AAC/D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,IAAI,IAAI,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC,CAAA;IAC3C,OAAO,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAC9C,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAC/D,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAClE,yEAAyE;IACzE,UAAU,CAAC,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,OAAO,CAAA;KAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAC3D;AAED,2EAA2E;AAC3E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAEnE;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE;IAC7C,MAAM,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAChC,MAAM,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;CACnD,GAAG,MAAM,GAAG,SAAS,CASrB;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,gBAAgB,EACzB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,CAAC,CAQ1B;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAElD"}
@@ -40,3 +40,13 @@ export async function resolveCompatiblePreset(presets, requested) {
40
40
  return presets.resolve(fallback);
41
41
  return presets.resolve(requested);
42
42
  }
43
+ /**
44
+ * The i18n dictionary id a roster preset's localized display text resolves
45
+ * under. The 0.1.2 line renamed the official PTC preset `code` → `ptc`, but
46
+ * the dictionary keys still use the legacy `code` id (`preset-name-code` /
47
+ * `preset-desc-code`), so the `/preset` picker's display lookup must bridge
48
+ * the roster id back. User-authored ids pass through untouched.
49
+ */
50
+ export function presetDisplayId(id) {
51
+ return id === 'ptc' ? 'code' : id;
52
+ }