@deepseek-harness-tui/dsh-tui 0.11.0 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (484) hide show
  1. package/README.md +55 -20
  2. package/assets/whale-girl/whale-girl-dark.png +0 -0
  3. package/assets/whale-girl/whale-girl-happy.png +0 -0
  4. package/assets/whale-girl/whale-girl.png +0 -0
  5. package/bin/dsh-tui.js +63 -3
  6. package/cordis.patch.yml +43 -20
  7. package/cordis.yml +6 -4
  8. package/lib/settings.json +1272 -0
  9. package/lib/types/activityPrefs.d.ts +24 -0
  10. package/lib/types/activityPrefs.d.ts.map +1 -1
  11. package/lib/types/activityPrefs.js +50 -1
  12. package/lib/types/adapter/channel/state.d.ts.map +1 -1
  13. package/lib/types/adapter/channel/state.js +3 -1
  14. package/lib/types/adapter/channel/ui-policy.d.ts +9 -2
  15. package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
  16. package/lib/types/adapter/channel/ui-policy.js +14 -1
  17. package/lib/types/adapter/kernel/replay.d.ts.map +1 -1
  18. package/lib/types/adapter/kernel/replay.js +2 -0
  19. package/lib/types/adapter/ports/channel-display.d.ts +12 -0
  20. package/lib/types/adapter/ports/channel-display.d.ts.map +1 -1
  21. package/lib/types/adapter/ports/channel-session.d.ts +38 -0
  22. package/lib/types/adapter/ports/channel-session.d.ts.map +1 -1
  23. package/lib/types/adapter/ports/channel-settings.d.ts +12 -0
  24. package/lib/types/adapter/ports/channel-settings.d.ts.map +1 -1
  25. package/lib/types/adapter/ports/channel-ui.d.ts +53 -7
  26. package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
  27. package/lib/types/adapter/ports/channel-view.d.ts +43 -12
  28. package/lib/types/adapter/ports/channel-view.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/commands.d.ts.map +1 -1
  32. package/lib/types/commands.js +2 -0
  33. package/lib/types/components/ActivityLine.d.ts +7 -2
  34. package/lib/types/components/ActivityLine.d.ts.map +1 -1
  35. package/lib/types/components/ActivityLine.js +0 -8
  36. package/lib/types/components/BalanceReportRow.d.ts +10 -2
  37. package/lib/types/components/BalanceReportRow.d.ts.map +1 -1
  38. package/lib/types/components/BalanceReportRow.js +18 -4
  39. package/lib/types/components/CompactionStatusRow.d.ts +24 -0
  40. package/lib/types/components/CompactionStatusRow.d.ts.map +1 -0
  41. package/lib/types/components/CompactionStatusRow.js +72 -0
  42. package/lib/types/components/GoalTodoPanel.js +2 -2
  43. package/lib/types/components/HelpMenu.d.ts +2 -2
  44. package/lib/types/components/HelpMenu.d.ts.map +1 -1
  45. package/lib/types/components/HelpMenu.js +5 -4
  46. package/lib/types/components/InlineMathParagraph.d.ts +22 -0
  47. package/lib/types/components/InlineMathParagraph.d.ts.map +1 -0
  48. package/lib/types/components/InlineMathParagraph.js +178 -0
  49. package/lib/types/components/LogoV2.d.ts +41 -3
  50. package/lib/types/components/LogoV2.d.ts.map +1 -1
  51. package/lib/types/components/LogoV2.js +148 -24
  52. package/lib/types/components/Markdown.d.ts +10 -3
  53. package/lib/types/components/Markdown.d.ts.map +1 -1
  54. package/lib/types/components/Markdown.js +47 -14
  55. package/lib/types/components/MathBlock.d.ts +13 -0
  56. package/lib/types/components/MathBlock.d.ts.map +1 -0
  57. package/lib/types/components/MathBlock.js +136 -0
  58. package/lib/types/components/MessageList.d.ts +10 -1
  59. package/lib/types/components/MessageList.d.ts.map +1 -1
  60. package/lib/types/components/MessageList.js +15 -5
  61. package/lib/types/components/MigratePicker.d.ts +30 -0
  62. package/lib/types/components/MigratePicker.d.ts.map +1 -0
  63. package/lib/types/components/MigratePicker.js +38 -0
  64. package/lib/types/components/PromptInput.d.ts +17 -0
  65. package/lib/types/components/PromptInput.d.ts.map +1 -1
  66. package/lib/types/components/PromptInput.js +96 -9
  67. package/lib/types/components/SplitDiffView.d.ts.map +1 -1
  68. package/lib/types/components/SplitDiffView.js +3 -1
  69. package/lib/types/components/StarPrompt.d.ts +53 -0
  70. package/lib/types/components/StarPrompt.d.ts.map +1 -0
  71. package/lib/types/components/StarPrompt.js +281 -0
  72. package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
  73. package/lib/types/components/StreamingMarkdown.js +20 -3
  74. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  75. package/lib/types/components/SubagentCard.js +12 -6
  76. package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
  77. package/lib/types/components/SubagentDetailScene.js +8 -3
  78. package/lib/types/components/TimelineRail.d.ts.map +1 -1
  79. package/lib/types/components/TimelineRail.js +9 -1
  80. package/lib/types/components/Whale.d.ts +17 -8
  81. package/lib/types/components/Whale.d.ts.map +1 -1
  82. package/lib/types/components/Whale.js +25 -15
  83. package/lib/types/components/WhaleGirl.d.ts +29 -0
  84. package/lib/types/components/WhaleGirl.d.ts.map +1 -0
  85. package/lib/types/components/WhaleGirl.js +32 -0
  86. package/lib/types/components/WorkingSpinner.d.ts +4 -1
  87. package/lib/types/components/WorkingSpinner.d.ts.map +1 -1
  88. package/lib/types/components/WorkingSpinner.js +2 -2
  89. package/lib/types/components/bigfont.d.ts +47 -18
  90. package/lib/types/components/bigfont.d.ts.map +1 -1
  91. package/lib/types/components/bigfont.js +55 -40
  92. package/lib/types/components/design-system/HintLine.d.ts +1 -2
  93. package/lib/types/components/design-system/HintLine.d.ts.map +1 -1
  94. package/lib/types/components/design-system/HintLine.js +1 -2
  95. package/lib/types/components/design-system/ThemeProvider.d.ts +6 -0
  96. package/lib/types/components/design-system/ThemeProvider.d.ts.map +1 -1
  97. package/lib/types/components/design-system/ThemeProvider.js +40 -1
  98. package/lib/types/components/maidPortrait.d.ts +44 -0
  99. package/lib/types/components/maidPortrait.d.ts.map +1 -0
  100. package/lib/types/components/maidPortrait.js +178 -0
  101. package/lib/types/components/mathPreview.d.ts +25 -0
  102. package/lib/types/components/mathPreview.d.ts.map +1 -0
  103. package/lib/types/components/mathPreview.js +48 -0
  104. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +2 -1
  105. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  106. package/lib/types/components/messages/AssistantThinkingMessage.js +4 -2
  107. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +2 -2
  108. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  109. package/lib/types/components/messages/AssistantToolUseMessage.js +31 -26
  110. package/lib/types/components/messages/TranscriptImages.d.ts.map +1 -1
  111. package/lib/types/components/messages/TranscriptImages.js +11 -1
  112. package/lib/types/components/questions/AskUserQuestionPanel.d.ts +14 -2
  113. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  114. package/lib/types/components/questions/AskUserQuestionPanel.js +80 -38
  115. package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
  116. package/lib/types/components/questions/PlanReviewPanel.js +3 -3
  117. package/lib/types/components/sessions/ForeignSessionRow.d.ts +34 -0
  118. package/lib/types/components/sessions/ForeignSessionRow.d.ts.map +1 -0
  119. package/lib/types/components/sessions/ForeignSessionRow.js +43 -0
  120. package/lib/types/components/sessions/SourceTabs.d.ts +52 -0
  121. package/lib/types/components/sessions/SourceTabs.d.ts.map +1 -0
  122. package/lib/types/components/sessions/SourceTabs.js +70 -0
  123. package/lib/types/components/splashEggs.d.ts +56 -0
  124. package/lib/types/components/splashEggs.d.ts.map +1 -0
  125. package/lib/types/components/splashEggs.js +67 -0
  126. package/lib/types/components/splashFonts.d.ts +119 -0
  127. package/lib/types/components/splashFonts.d.ts.map +1 -0
  128. package/lib/types/components/splashFonts.js +267 -0
  129. package/lib/types/components/splashLayout.d.ts +41 -0
  130. package/lib/types/components/splashLayout.d.ts.map +1 -0
  131. package/lib/types/components/splashLayout.js +40 -0
  132. package/lib/types/components/whaleGirlSprite.d.ts +17 -0
  133. package/lib/types/components/whaleGirlSprite.d.ts.map +1 -0
  134. package/lib/types/components/whaleGirlSprite.js +47 -0
  135. package/lib/types/deepseekPricing.d.ts +74 -0
  136. package/lib/types/deepseekPricing.d.ts.map +1 -1
  137. package/lib/types/deepseekPricing.js +110 -11
  138. package/lib/types/dsh-adapter/activity-store.d.ts +221 -0
  139. package/lib/types/dsh-adapter/activity-store.d.ts.map +1 -0
  140. package/lib/types/dsh-adapter/activity-store.js +359 -0
  141. package/lib/types/dsh-adapter/channel/action-readiness.d.ts +1 -1
  142. package/lib/types/dsh-adapter/channel/action-readiness.d.ts.map +1 -1
  143. package/lib/types/dsh-adapter/channel/action-readiness.js +6 -1
  144. package/lib/types/dsh-adapter/channel/background-action.d.ts +2 -1
  145. package/lib/types/dsh-adapter/channel/background-action.d.ts.map +1 -1
  146. package/lib/types/dsh-adapter/channel/background-action.js +2 -0
  147. package/lib/types/dsh-adapter/channel/binding-events.d.ts +15 -14
  148. package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
  149. package/lib/types/dsh-adapter/channel/binding-events.js +70 -21
  150. package/lib/types/dsh-adapter/channel/compaction.d.ts +2 -2
  151. package/lib/types/dsh-adapter/channel/compaction.d.ts.map +1 -1
  152. package/lib/types/dsh-adapter/channel/compaction.js +35 -4
  153. package/lib/types/dsh-adapter/channel/local-actions.d.ts.map +1 -1
  154. package/lib/types/dsh-adapter/channel/local-actions.js +6 -1
  155. package/lib/types/dsh-adapter/channel/model-switch.d.ts +1 -2
  156. package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
  157. package/lib/types/dsh-adapter/channel/model-switch.js +6 -2
  158. package/lib/types/dsh-adapter/channel/paths.d.ts.map +1 -1
  159. package/lib/types/dsh-adapter/channel/paths.js +7 -1
  160. package/lib/types/dsh-adapter/channel/preferences.d.ts +1 -1
  161. package/lib/types/dsh-adapter/channel/preferences.d.ts.map +1 -1
  162. package/lib/types/dsh-adapter/channel/preferences.js +16 -0
  163. package/lib/types/dsh-adapter/channel/projection.d.ts +1 -2
  164. package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
  165. package/lib/types/dsh-adapter/channel/projection.js +127 -17
  166. package/lib/types/dsh-adapter/channel/question-record.d.ts +76 -0
  167. package/lib/types/dsh-adapter/channel/question-record.d.ts.map +1 -0
  168. package/lib/types/dsh-adapter/channel/question-record.js +107 -0
  169. package/lib/types/dsh-adapter/channel/session-adoption.d.ts +1 -1
  170. package/lib/types/dsh-adapter/channel/session-adoption.d.ts.map +1 -1
  171. package/lib/types/dsh-adapter/channel/session-adoption.js +1 -0
  172. package/lib/types/dsh-adapter/channel/session-lineage.d.ts +42 -0
  173. package/lib/types/dsh-adapter/channel/session-lineage.d.ts.map +1 -0
  174. package/lib/types/dsh-adapter/channel/session-lineage.js +51 -0
  175. package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts +3 -1
  176. package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts.map +1 -1
  177. package/lib/types/dsh-adapter/channel/session-live-adoption.js +10 -3
  178. package/lib/types/dsh-adapter/channel/session-metadata.d.ts +2 -1
  179. package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
  180. package/lib/types/dsh-adapter/channel/session-metadata.js +43 -9
  181. package/lib/types/dsh-adapter/channel/session-reset.d.ts +1 -1
  182. package/lib/types/dsh-adapter/channel/session-reset.d.ts.map +1 -1
  183. package/lib/types/dsh-adapter/channel/session-reset.js +7 -1
  184. package/lib/types/dsh-adapter/channel/session-resume.d.ts +2 -1
  185. package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
  186. package/lib/types/dsh-adapter/channel/session-resume.js +5 -2
  187. package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
  188. package/lib/types/dsh-adapter/channel/settings-host.js +8 -0
  189. package/lib/types/dsh-adapter/channel/state.d.ts +19 -1
  190. package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
  191. package/lib/types/dsh-adapter/channel/state.js +8 -3
  192. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts +32 -17
  193. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
  194. package/lib/types/dsh-adapter/channel/subagent-projection.js +309 -8
  195. package/lib/types/dsh-adapter/channel/types.d.ts +1 -1
  196. package/lib/types/dsh-adapter/channel/types.d.ts.map +1 -1
  197. package/lib/types/dsh-adapter/channel.d.ts +1 -1
  198. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  199. package/lib/types/dsh-adapter/channel.js +34 -18
  200. package/lib/types/dsh-adapter/compat/index.d.ts +1 -1
  201. package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -1
  202. package/lib/types/dsh-adapter/compat/index.js +1 -1
  203. package/lib/types/dsh-adapter/compat/messages.d.ts +6 -0
  204. package/lib/types/dsh-adapter/compat/messages.d.ts.map +1 -1
  205. package/lib/types/dsh-adapter/compat/messages.js +9 -0
  206. package/lib/types/dsh-adapter/compat/sessionLog.d.ts +18 -0
  207. package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -1
  208. package/lib/types/dsh-adapter/compat/sessionLog.js +18 -3
  209. package/lib/types/dsh-adapter/compat/settings.d.ts +2 -0
  210. package/lib/types/dsh-adapter/compat/settings.d.ts.map +1 -1
  211. package/lib/types/dsh-adapter/compat/settings.js +14 -0
  212. package/lib/types/dsh-adapter/contract.d.ts +5 -4
  213. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  214. package/lib/types/dsh-adapter/contract.js +9 -5
  215. package/lib/types/dsh-adapter/index.d.ts +36 -1
  216. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  217. package/lib/types/dsh-adapter/index.js +22 -6
  218. package/lib/types/dsh-adapter/migrate/adapters/claude-code.d.ts +3 -0
  219. package/lib/types/dsh-adapter/migrate/adapters/claude-code.d.ts.map +1 -0
  220. package/lib/types/dsh-adapter/migrate/adapters/claude-code.js +131 -0
  221. package/lib/types/dsh-adapter/migrate/adapters/claude-code.parse.d.ts +17 -0
  222. package/lib/types/dsh-adapter/migrate/adapters/claude-code.parse.d.ts.map +1 -0
  223. package/lib/types/dsh-adapter/migrate/adapters/claude-code.parse.js +329 -0
  224. package/lib/types/dsh-adapter/migrate/adapters/codex.d.ts +3 -0
  225. package/lib/types/dsh-adapter/migrate/adapters/codex.d.ts.map +1 -0
  226. package/lib/types/dsh-adapter/migrate/adapters/codex.js +102 -0
  227. package/lib/types/dsh-adapter/migrate/adapters/codex.parse.d.ts +16 -0
  228. package/lib/types/dsh-adapter/migrate/adapters/codex.parse.d.ts.map +1 -0
  229. package/lib/types/dsh-adapter/migrate/adapters/codex.parse.js +289 -0
  230. package/lib/types/dsh-adapter/migrate/adapters/grok-build.d.ts +3 -0
  231. package/lib/types/dsh-adapter/migrate/adapters/grok-build.d.ts.map +1 -0
  232. package/lib/types/dsh-adapter/migrate/adapters/grok-build.js +117 -0
  233. package/lib/types/dsh-adapter/migrate/adapters/grok-build.parse.d.ts +13 -0
  234. package/lib/types/dsh-adapter/migrate/adapters/grok-build.parse.d.ts.map +1 -0
  235. package/lib/types/dsh-adapter/migrate/adapters/grok-build.parse.js +178 -0
  236. package/lib/types/dsh-adapter/migrate/adapters/omp.d.ts +3 -0
  237. package/lib/types/dsh-adapter/migrate/adapters/omp.d.ts.map +1 -0
  238. package/lib/types/dsh-adapter/migrate/adapters/omp.js +133 -0
  239. package/lib/types/dsh-adapter/migrate/adapters/scan-fs.d.ts +60 -0
  240. package/lib/types/dsh-adapter/migrate/adapters/scan-fs.d.ts.map +1 -0
  241. package/lib/types/dsh-adapter/migrate/adapters/scan-fs.js +178 -0
  242. package/lib/types/dsh-adapter/migrate/adapters/scan.d.ts +8 -0
  243. package/lib/types/dsh-adapter/migrate/adapters/scan.d.ts.map +1 -0
  244. package/lib/types/dsh-adapter/migrate/adapters/scan.js +40 -0
  245. package/lib/types/dsh-adapter/migrate/adapters/zcode.d.ts +3 -0
  246. package/lib/types/dsh-adapter/migrate/adapters/zcode.d.ts.map +1 -0
  247. package/lib/types/dsh-adapter/migrate/adapters/zcode.js +93 -0
  248. package/lib/types/dsh-adapter/migrate/adapters/zcode.parse.d.ts +9 -0
  249. package/lib/types/dsh-adapter/migrate/adapters/zcode.parse.d.ts.map +1 -0
  250. package/lib/types/dsh-adapter/migrate/adapters/zcode.parse.js +89 -0
  251. package/lib/types/dsh-adapter/migrate/bin-path.d.ts +6 -0
  252. package/lib/types/dsh-adapter/migrate/bin-path.d.ts.map +1 -0
  253. package/lib/types/dsh-adapter/migrate/bin-path.js +30 -0
  254. package/lib/types/dsh-adapter/migrate/browse.d.ts +42 -0
  255. package/lib/types/dsh-adapter/migrate/browse.d.ts.map +1 -0
  256. package/lib/types/dsh-adapter/migrate/browse.js +90 -0
  257. package/lib/types/dsh-adapter/migrate/cli.d.ts +9 -0
  258. package/lib/types/dsh-adapter/migrate/cli.d.ts.map +1 -0
  259. package/lib/types/dsh-adapter/migrate/cli.js +106 -0
  260. package/lib/types/dsh-adapter/migrate/import-one.d.ts +89 -0
  261. package/lib/types/dsh-adapter/migrate/import-one.d.ts.map +1 -0
  262. package/lib/types/dsh-adapter/migrate/import-one.js +133 -0
  263. package/lib/types/dsh-adapter/migrate/index.d.ts +35 -0
  264. package/lib/types/dsh-adapter/migrate/index.d.ts.map +1 -0
  265. package/lib/types/dsh-adapter/migrate/index.js +107 -0
  266. package/lib/types/dsh-adapter/migrate/parse/injection.d.ts +40 -0
  267. package/lib/types/dsh-adapter/migrate/parse/injection.d.ts.map +1 -0
  268. package/lib/types/dsh-adapter/migrate/parse/injection.js +127 -0
  269. package/lib/types/dsh-adapter/migrate/parse/jsonl.d.ts +28 -0
  270. package/lib/types/dsh-adapter/migrate/parse/jsonl.d.ts.map +1 -0
  271. package/lib/types/dsh-adapter/migrate/parse/jsonl.js +40 -0
  272. package/lib/types/dsh-adapter/migrate/parse/role-turns.d.ts +28 -0
  273. package/lib/types/dsh-adapter/migrate/parse/role-turns.d.ts.map +1 -0
  274. package/lib/types/dsh-adapter/migrate/parse/role-turns.js +50 -0
  275. package/lib/types/dsh-adapter/migrate/parse/title.d.ts +18 -0
  276. package/lib/types/dsh-adapter/migrate/parse/title.d.ts.map +1 -0
  277. package/lib/types/dsh-adapter/migrate/parse/title.js +29 -0
  278. package/lib/types/dsh-adapter/migrate/parse/tools.d.ts +62 -0
  279. package/lib/types/dsh-adapter/migrate/parse/tools.d.ts.map +1 -0
  280. package/lib/types/dsh-adapter/migrate/parse/tools.js +110 -0
  281. package/lib/types/dsh-adapter/migrate/picker.d.ts +64 -0
  282. package/lib/types/dsh-adapter/migrate/picker.d.ts.map +1 -0
  283. package/lib/types/dsh-adapter/migrate/picker.js +86 -0
  284. package/lib/types/dsh-adapter/migrate/recent-agents.d.ts +40 -0
  285. package/lib/types/dsh-adapter/migrate/recent-agents.d.ts.map +1 -0
  286. package/lib/types/dsh-adapter/migrate/recent-agents.js +100 -0
  287. package/lib/types/dsh-adapter/migrate/sessionize.d.ts +39 -0
  288. package/lib/types/dsh-adapter/migrate/sessionize.d.ts.map +1 -0
  289. package/lib/types/dsh-adapter/migrate/sessionize.js +271 -0
  290. package/lib/types/dsh-adapter/migrate/types.d.ts +176 -0
  291. package/lib/types/dsh-adapter/migrate/types.d.ts.map +1 -0
  292. package/lib/types/dsh-adapter/migrate/types.js +11 -0
  293. package/lib/types/dsh-adapter/migrate/uuid.d.ts +7 -0
  294. package/lib/types/dsh-adapter/migrate/uuid.d.ts.map +1 -0
  295. package/lib/types/dsh-adapter/migrate/uuid.js +25 -0
  296. package/lib/types/dsh-adapter/plugin.d.ts +5 -3
  297. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  298. package/lib/types/dsh-adapter/plugin.js +168 -372
  299. package/lib/types/dsh-adapter/providerWizard.d.ts +17 -0
  300. package/lib/types/dsh-adapter/providerWizard.d.ts.map +1 -1
  301. package/lib/types/dsh-adapter/providerWizard.js +254 -66
  302. package/lib/types/dsh-adapter/questions.d.ts +22 -15
  303. package/lib/types/dsh-adapter/questions.d.ts.map +1 -1
  304. package/lib/types/dsh-adapter/questions.js +47 -45
  305. package/lib/types/dsh-adapter/sessions/digest.d.ts +11 -6
  306. package/lib/types/dsh-adapter/sessions/digest.d.ts.map +1 -1
  307. package/lib/types/dsh-adapter/sessions/digest.js +20 -13
  308. package/lib/types/dsh-adapter/sessions/frames.d.ts +3 -1
  309. package/lib/types/dsh-adapter/sessions/frames.d.ts.map +1 -1
  310. package/lib/types/dsh-adapter/sessions/frames.js +5 -4
  311. package/lib/types/dsh-adapter/sessions/list.d.ts +6 -1
  312. package/lib/types/dsh-adapter/sessions/list.d.ts.map +1 -1
  313. package/lib/types/dsh-adapter/sessions/list.js +188 -164
  314. package/lib/types/dsh-adapter/sessions/recovery.d.ts +16 -0
  315. package/lib/types/dsh-adapter/sessions/recovery.d.ts.map +1 -0
  316. package/lib/types/dsh-adapter/sessions/recovery.js +108 -0
  317. package/lib/types/dsh-adapter/sessions/snapshot.d.ts +7 -0
  318. package/lib/types/dsh-adapter/sessions/snapshot.d.ts.map +1 -0
  319. package/lib/types/dsh-adapter/sessions/snapshot.js +90 -0
  320. package/lib/types/dsh-adapter/sessions/store.d.ts +10 -4
  321. package/lib/types/dsh-adapter/sessions/store.d.ts.map +1 -1
  322. package/lib/types/dsh-adapter/sessions/store.js +62 -25
  323. package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
  324. package/lib/types/dsh-adapter/settings-sections.js +7 -4
  325. package/lib/types/dsh-adapter/sideQuestion.d.ts +41 -2
  326. package/lib/types/dsh-adapter/sideQuestion.d.ts.map +1 -1
  327. package/lib/types/dsh-adapter/sideQuestion.js +98 -2
  328. package/lib/types/dsh-adapter/subagents.d.ts +44 -6
  329. package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
  330. package/lib/types/dsh-adapter/subagents.js +163 -26
  331. package/lib/types/herdr.d.ts +2 -0
  332. package/lib/types/herdr.d.ts.map +1 -1
  333. package/lib/types/herdr.js +9 -3
  334. package/lib/types/history.d.ts +13 -1
  335. package/lib/types/history.d.ts.map +1 -1
  336. package/lib/types/history.js +15 -2
  337. package/lib/types/i18n.d.ts +512 -41
  338. package/lib/types/i18n.d.ts.map +1 -1
  339. package/lib/types/i18n.js +199 -20
  340. package/lib/types/ink/components/App.d.ts +2 -2
  341. package/lib/types/ink/components/App.d.ts.map +1 -1
  342. package/lib/types/ink/components/App.js +5 -1
  343. package/lib/types/ink/components/Image.d.ts +14 -1
  344. package/lib/types/ink/components/Image.d.ts.map +1 -1
  345. package/lib/types/ink/components/Image.js +2 -2
  346. package/lib/types/ink/events/input-event.js +3 -3
  347. package/lib/types/ink/hooks/use-terminal-images.d.ts +12 -0
  348. package/lib/types/ink/hooks/use-terminal-images.d.ts.map +1 -1
  349. package/lib/types/ink/hooks/use-terminal-images.js +13 -0
  350. package/lib/types/ink/ink.d.ts +6 -0
  351. package/lib/types/ink/ink.d.ts.map +1 -1
  352. package/lib/types/ink/ink.js +16 -1
  353. package/lib/types/ink/kitty-graphics.d.ts +44 -3
  354. package/lib/types/ink/kitty-graphics.d.ts.map +1 -1
  355. package/lib/types/ink/kitty-graphics.js +184 -23
  356. package/lib/types/ink/log-update.d.ts.map +1 -1
  357. package/lib/types/ink/log-update.js +19 -1
  358. package/lib/types/ink/output.d.ts +24 -2
  359. package/lib/types/ink/output.d.ts.map +1 -1
  360. package/lib/types/ink/output.js +83 -5
  361. package/lib/types/ink/parse-keypress.d.ts +26 -1
  362. package/lib/types/ink/parse-keypress.d.ts.map +1 -1
  363. package/lib/types/ink/parse-keypress.js +156 -13
  364. package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
  365. package/lib/types/ink/render-node-to-output.js +8 -1
  366. package/lib/types/ink/screen.d.ts +24 -0
  367. package/lib/types/ink/screen.d.ts.map +1 -1
  368. package/lib/types/ink/screen.js +89 -0
  369. package/lib/types/ink/selection.d.ts +68 -18
  370. package/lib/types/ink/selection.d.ts.map +1 -1
  371. package/lib/types/ink/selection.js +178 -31
  372. package/lib/types/ink/sixel-codec.d.ts +12 -1
  373. package/lib/types/ink/sixel-codec.d.ts.map +1 -1
  374. package/lib/types/ink/sixel-codec.js +29 -5
  375. package/lib/types/ink/sixel-graphics.d.ts.map +1 -1
  376. package/lib/types/ink/sixel-graphics.js +5 -3
  377. package/lib/types/ink/styles.d.ts +9 -0
  378. package/lib/types/ink/styles.d.ts.map +1 -1
  379. package/lib/types/ink/terminal-image.d.ts +8 -0
  380. package/lib/types/ink/terminal-image.d.ts.map +1 -1
  381. package/lib/types/ink/terminal-querier.d.ts +7 -1
  382. package/lib/types/ink/terminal-querier.d.ts.map +1 -1
  383. package/lib/types/ink/terminal-querier.js +12 -2
  384. package/lib/types/ink/timeline-rail.d.ts +5 -0
  385. package/lib/types/ink/timeline-rail.d.ts.map +1 -1
  386. package/lib/types/math/inline-layout.d.ts +29 -0
  387. package/lib/types/math/inline-layout.d.ts.map +1 -0
  388. package/lib/types/math/inline-layout.js +106 -0
  389. package/lib/types/math/layout.d.ts +58 -0
  390. package/lib/types/math/layout.d.ts.map +1 -0
  391. package/lib/types/math/layout.js +59 -0
  392. package/lib/types/math/renderer.d.ts +64 -0
  393. package/lib/types/math/renderer.d.ts.map +1 -0
  394. package/lib/types/math/renderer.js +256 -0
  395. package/lib/types/screens/Chat.d.ts +17 -1
  396. package/lib/types/screens/Chat.d.ts.map +1 -1
  397. package/lib/types/screens/Chat.js +618 -57
  398. package/lib/types/screens/SessionSupervisor.d.ts +2 -1
  399. package/lib/types/screens/SessionSupervisor.d.ts.map +1 -1
  400. package/lib/types/screens/SessionSupervisor.js +156 -19
  401. package/lib/types/screens/Settings.d.ts.map +1 -1
  402. package/lib/types/screens/Settings.js +49 -11
  403. package/lib/types/screens/StatusLine.d.ts +5 -1
  404. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  405. package/lib/types/screens/StatusLine.js +47 -17
  406. package/lib/types/screens/chatOverlay.d.ts +5 -0
  407. package/lib/types/screens/chatOverlay.d.ts.map +1 -1
  408. package/lib/types/screens/chatOverlay.js +1 -0
  409. package/lib/types/screens/sessionSupervisor/ForeignSessionPanes.d.ts +47 -0
  410. package/lib/types/screens/sessionSupervisor/ForeignSessionPanes.d.ts.map +1 -0
  411. package/lib/types/screens/sessionSupervisor/ForeignSessionPanes.js +65 -0
  412. package/lib/types/screens/sessionSupervisor/model.d.ts +12 -0
  413. package/lib/types/screens/sessionSupervisor/model.d.ts.map +1 -1
  414. package/lib/types/screens/sessionSupervisor/model.js +26 -0
  415. package/lib/types/screens/sessionSupervisor/useForeignSessions.d.ts +107 -0
  416. package/lib/types/screens/sessionSupervisor/useForeignSessions.d.ts.map +1 -0
  417. package/lib/types/screens/sessionSupervisor/useForeignSessions.js +312 -0
  418. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts +4 -1
  419. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts.map +1 -1
  420. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.js +97 -14
  421. package/lib/types/sessionHistory.d.ts +2 -2
  422. package/lib/types/sessionHistory.d.ts.map +1 -1
  423. package/lib/types/sessionHistory.js +31 -5
  424. package/lib/types/settings/definitions.d.ts +681 -0
  425. package/lib/types/settings/definitions.d.ts.map +1 -0
  426. package/lib/types/settings/definitions.js +511 -0
  427. package/lib/types/starAction.d.ts +44 -0
  428. package/lib/types/starAction.d.ts.map +1 -0
  429. package/lib/types/starAction.js +52 -0
  430. package/lib/types/terminal-utils/latex.d.ts +10 -0
  431. package/lib/types/terminal-utils/latex.d.ts.map +1 -0
  432. package/lib/types/terminal-utils/latex.js +1417 -0
  433. package/lib/types/terminal-utils/markdown.d.ts +3 -1
  434. package/lib/types/terminal-utils/markdown.d.ts.map +1 -1
  435. package/lib/types/terminal-utils/markdown.js +26 -1
  436. package/lib/types/terminal-utils/math.d.ts +66 -0
  437. package/lib/types/terminal-utils/math.d.ts.map +1 -0
  438. package/lib/types/terminal-utils/math.js +337 -0
  439. package/lib/types/tips.d.ts.map +1 -1
  440. package/lib/types/tips.js +6 -0
  441. package/lib/types/tuiDisplayPrefs.d.ts +67 -0
  442. package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
  443. package/lib/types/tuiDisplayPrefs.js +59 -0
  444. package/lib/types/ui.d.ts +1 -1
  445. package/lib/types/ui.d.ts.map +1 -1
  446. package/lib/types/ui.js +1 -1
  447. package/lib/types/usageStats.d.ts +98 -0
  448. package/lib/types/usageStats.d.ts.map +1 -0
  449. package/lib/types/usageStats.js +169 -0
  450. package/lib/types/utils/bmp.d.ts +17 -0
  451. package/lib/types/utils/bmp.d.ts.map +1 -0
  452. package/lib/types/utils/bmp.js +154 -0
  453. package/lib/types/utils/clipboard.d.ts +14 -2
  454. package/lib/types/utils/clipboard.d.ts.map +1 -1
  455. package/lib/types/utils/clipboard.js +143 -8
  456. package/lib/types/utils/fold-long-lines.d.ts +1 -1
  457. package/lib/types/utils/fold-long-lines.d.ts.map +1 -1
  458. package/lib/types/utils/fold-long-lines.js +3 -2
  459. package/lib/types/utils/keymap.d.ts +4 -1
  460. package/lib/types/utils/keymap.d.ts.map +1 -1
  461. package/lib/types/utils/keymap.js +8 -0
  462. package/lib/types/utils/modifiers.d.ts +4 -3
  463. package/lib/types/utils/modifiers.d.ts.map +1 -1
  464. package/lib/types/utils/modifiers.js +4 -3
  465. package/lib/types/working-activity.d.ts +10 -9
  466. package/lib/types/working-activity.d.ts.map +1 -1
  467. package/lib/types/working-activity.js +17 -10
  468. package/node_modules/@dsh-tui-vendor/mathjax-tex-svg/LICENSE +202 -0
  469. package/node_modules/@dsh-tui-vendor/mathjax-tex-svg/NOTICE +20 -0
  470. package/node_modules/@dsh-tui-vendor/mathjax-tex-svg/index.d.ts +16 -0
  471. package/node_modules/@dsh-tui-vendor/mathjax-tex-svg/lib/bundled-packages.json +4 -0
  472. package/node_modules/@dsh-tui-vendor/mathjax-tex-svg/lib/index.mjs +20 -0
  473. package/node_modules/@dsh-tui-vendor/mathjax-tex-svg/lib/index.mjs.LEGAL.txt +35 -0
  474. package/node_modules/@dsh-tui-vendor/mathjax-tex-svg/package.json +29 -0
  475. package/package.json +117 -99
  476. package/lib/types/components/design-system/KeyboardShortcutHint.d.ts +0 -19
  477. package/lib/types/components/design-system/KeyboardShortcutHint.d.ts.map +0 -1
  478. package/lib/types/components/design-system/KeyboardShortcutHint.js +0 -14
  479. package/lib/types/dsh-adapter/channel/activity.d.ts +0 -20
  480. package/lib/types/dsh-adapter/channel/activity.d.ts.map +0 -1
  481. package/lib/types/dsh-adapter/channel/activity.js +0 -113
  482. package/lib/types/terminal-utils/terminal.d.ts +0 -18
  483. package/lib/types/terminal-utils/terminal.d.ts.map +0 -1
  484. package/lib/types/terminal-utils/terminal.js +0 -96
@@ -24,7 +24,7 @@ import { imagePathMediaType, parsePastedImagePath, stageClipboardFilePaths } fro
24
24
  import { editInExternalEditor } from '../utils/externalEditor.js';
25
25
  import { setPromptEditorNode, EditorButton } from './PromptEditor.js';
26
26
  import { isHiddenCommandName, parseCommandName } from '../commands.js';
27
- import { appendHistory } from '../history.js';
27
+ import { appendHistory, HISTORY_LIMIT, loadHistoryOldestFirst } from '../history.js';
28
28
  import { mentionAtCaret } from '../utils/mentions.js';
29
29
  import { preserveSelection } from '../utils/fileSuggestions.js';
30
30
  import { isMod } from '../utils/modifiers.js';
@@ -35,7 +35,6 @@ import { HelpMenu } from './HelpMenu.js';
35
35
  import { OverlayAbove } from './OverlayAbove.js';
36
36
  import { SuggestionCard, cardContentWidth } from './SuggestionCard.js';
37
37
  import { filterLiveImageBindings, isUsableDraftSnapshot, resolveBindingGeneration, } from './promptDraftCache.js';
38
- const HISTORY_LIMIT = 50;
39
38
  /**
40
39
  * Visible text of the session-entry control at the head of the input row:
41
40
  * U+2338 APL FUNCTIONAL SYMBOL QUAD COLON plus a separator space.
@@ -74,17 +73,58 @@ const isBigInput = (text) => text.split('\n').length >= FOLD_MIN_LINES || text.l
74
73
  * Strip terminal controls and expand tabs at ingress while preserving newlines.
75
74
  */
76
75
  const EDITABLE_CONTROL = /[\u0000-\u0009\u000b-\u001f\u007f]/u;
77
- /** Normalize editable text so no terminal control characters remain in state. */
78
- function sanitizeEditableText(text) {
76
+ /**
77
+ * Raw win32-input-mode records (`CSI Vk;Sc;Uc;Kd;Cs;Rc _`) that reached the
78
+ * editable buffer as text instead of being translated. `stripAnsi` consumes
79
+ * the record head and leaves its terminating `_` in the draft — the stray
80
+ * underscore users see after a multi-line paste (issue #1090). Only the full
81
+ * record grammar (exactly five `;` separators) matches, so a real `_` and
82
+ * ordinary bracket text survive untouched.
83
+ */
84
+ const WIN32_RECORD_RESIDUE = /\u001b\[\d*(?:;\d*){5}_/gu;
85
+ /**
86
+ * The same record with its ESC byte missing: what a record split across
87
+ * reads leaves behind when the escape timer flushed the prefix before the
88
+ * tail arrived. Printable, so it is stripped only from paste payloads
89
+ * ({@link sanitizePastedText}) — and only when the same payload also carries
90
+ * a full ESC-bearing record as in-payload evidence of that split; typed text
91
+ * and literal clipboard/bracketed-paste bytes are left untouched.
92
+ */
93
+ const WIN32_RECORD_RESIDUE_TAIL = /\[\d*(?:;\d*){5}_/gu;
94
+ /**
95
+ * Normalize editable text so no terminal control characters remain in state.
96
+ */
97
+ export function sanitizeEditableText(text) {
79
98
  // Fast path for ordinary and multi-line drafts: newline is intentionally
80
- // absent from the probe, so a large clean paste returns without regex work.
99
+ // absent from the probe, so large clean text returns without the
100
+ // stripAnsi/control-normalization passes.
81
101
  if (!EDITABLE_CONTROL.test(text))
82
102
  return text;
83
- return stripAnsi(text)
103
+ // Record residue goes first: `stripAnsi` would consume the CSI head and
104
+ // leave only the terminating `_` behind.
105
+ return stripAnsi(text.replace(WIN32_RECORD_RESIDUE, ''))
84
106
  .replace(/\r\n?/gu, '\n')
85
107
  .replace(/\t/gu, ' ')
86
108
  .replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/gu, '');
87
109
  }
110
+ /**
111
+ * Paste-payload ingress: strip the ESC-less tail of a split record before
112
+ * normalizing. The tail is printable, so it survives `sanitizeEditableText`'s
113
+ * control probe untouched; typed text keeps it because only a paste payload
114
+ * can carry a partial record.
115
+ *
116
+ * The five separators only prove the *shape*, not that a record was split:
117
+ * a user can legitimately paste the literal `[13;28;13;1;0;1_`. Strip the
118
+ * ESC-less form only when the same payload also carries a full ESC-bearing
119
+ * record — only then is there in-payload evidence of a split stream.
120
+ * Otherwise the bytes are ordinary text and must survive verbatim.
121
+ */
122
+ export function sanitizePastedText(text) {
123
+ // Probe with String#match: the /g detection regex carries lastIndex state
124
+ // across `.test` calls, so a previous success could skip a later match.
125
+ const hasRecordStream = text.match(WIN32_RECORD_RESIDUE) !== null;
126
+ return sanitizeEditableText(hasRecordStream ? text.replace(WIN32_RECORD_RESIDUE_TAIL, '') : text);
127
+ }
88
128
  const COMPOSER_IMAGE_TOKEN = /\[Image #\d+\]/gu;
89
129
  /** Format label for one image media type, matching the image preview card's
90
130
  * title (`JPEG`, `PNG`, `WEBP`, `GIF`). */
@@ -535,6 +575,8 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
535
575
  const history = React.useRef([]);
536
576
  const historyIndex = React.useRef(-1);
537
577
  const historyDraft = React.useRef({ text: '', images: [] });
578
+ /** The persisted history is read lazily, once per mount (see seedHistory). */
579
+ const historySeeded = React.useRef(false);
538
580
  /** Visible `[Image #N]` labels are presentation only; this sidecar carries
539
581
  * the non-reusable capability for the current draft. History/rewind text
540
582
  * restored without this map can never bind to a later image by accident. */
@@ -1096,7 +1138,26 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
1096
1138
  return;
1097
1139
  }
1098
1140
  };
1141
+ /**
1142
+ * Seed the walk with the persisted history (issue #986). `↑`/`↓` used to
1143
+ * see only what this process submitted, so a restart lost every earlier
1144
+ * entry. Seeding before the first push keeps ONE chronological list —
1145
+ * persisted entries first, this run's submits behind them — instead of two
1146
+ * lists to merge at recall time. Restored text carries no image capability
1147
+ * (the file stores text only), which is also what keeps a recalled entry
1148
+ * from binding to a later staged image by accident.
1149
+ */
1150
+ const seedHistory = () => {
1151
+ if (historySeeded.current)
1152
+ return;
1153
+ historySeeded.current = true;
1154
+ history.current = loadHistoryOldestFirst().map(entry => ({ text: entry.text, images: [] }));
1155
+ historyIndex.current = -1;
1156
+ };
1099
1157
  const rememberHistory = (text, images) => {
1158
+ // Both entries into the walk (a submit and ↑) must see the persisted
1159
+ // prefix, so seed here rather than merging two lists later.
1160
+ seedHistory();
1100
1161
  history.current.push({
1101
1162
  text,
1102
1163
  images: images.map(image => ({ ...image })),
@@ -1203,6 +1264,30 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
1203
1264
  setFileSelected(0);
1204
1265
  channel.notify(t('input-retracted'), { timeoutMs: 2000 });
1205
1266
  };
1267
+ /**
1268
+ * Withdraw the queued copy of the text `↑` just recalled (issue #986): the
1269
+ * message is still parked in the inbox, so editing it and sending again
1270
+ * would run the same text twice. Alt+Up withdraws explicitly; walking the
1271
+ * history to the same text has to land in the same place. The newest match
1272
+ * wins — `↑` walks newest-first and the queue is FIFO. A message the
1273
+ * running turn already claimed cannot be withdrawn, and saying so beats
1274
+ * pretending it was.
1275
+ */
1276
+ const retractRecalledCopy = (text) => {
1277
+ let target;
1278
+ for (const item of channel.pending) {
1279
+ if (item.text === text)
1280
+ target = item;
1281
+ }
1282
+ if (target === undefined)
1283
+ return;
1284
+ if (channel.removePending(target.id)) {
1285
+ channel.notify(t('input-retracted'), { timeoutMs: 2000 });
1286
+ }
1287
+ else {
1288
+ channel.notify(t('input-cannot-retract'), { color: 'warning', timeoutMs: 2500 });
1289
+ }
1290
+ };
1206
1291
  /**
1207
1292
  * Ctrl+Enter: abort the running turn and send the input immediately — the
1208
1293
  * model stops what it is doing and starts on this message right away.
@@ -1644,7 +1729,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
1644
1729
  // Newlines remain data — they are NOT Enter — so this branch runs before
1645
1730
  // the whole-line submit rule.
1646
1731
  if (event?.isPasted && input.length > 0) {
1647
- const text = sanitizeEditableText(input.replace(/\r\n/g, '\n').replace(/\r/g, '\n'));
1732
+ const text = sanitizePastedText(input.replace(/\r\n/g, '\n').replace(/\r/g, '\n'));
1648
1733
  // Desktop drops reach the TUI as pasted text (Ghostty forwards
1649
1734
  // Shell.escape(path) through the PTY with no drop boundary). Only a
1650
1735
  // paste that IS one unambiguous existing local image path stages as
@@ -1713,7 +1798,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
1713
1798
  return;
1714
1799
  }
1715
1800
  if (content.kind === 'unavailable') {
1716
- channel.notify(t('input-clipboard-unavailable'), { color: 'warning' });
1801
+ channel.notify(t(content.wsl === true ? 'input-clipboard-unavailable-wsl' : 'input-clipboard-unavailable'), { color: 'warning' });
1717
1802
  return;
1718
1803
  }
1719
1804
  if (content.kind === 'image') {
@@ -1802,7 +1887,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
1802
1887
  return;
1803
1888
  // Insert against the LIVE input state: the read above resolved
1804
1889
  // asynchronously and the user may have typed while waiting.
1805
- const text = sanitizeEditableText(formatClipboardInsert(content));
1890
+ const text = sanitizePastedText(formatClipboardInsert(content));
1806
1891
  const { at } = insertClipboardAtCaret(text);
1807
1892
  // Same fold as bracketed paste — but never inside the expanded
1808
1893
  // editor (plain text there, see the isPasted branch).
@@ -2086,6 +2171,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
2086
2171
  setSelectedCommand(index => index <= 0 ? suggestions.length - 1 : index - 1);
2087
2172
  return;
2088
2173
  }
2174
+ seedHistory();
2089
2175
  if (history.current.length === 0)
2090
2176
  return;
2091
2177
  if (historyIndex.current < 0) {
@@ -2101,6 +2187,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
2101
2187
  const entry = history.current[historyIndex.current];
2102
2188
  if (entry === undefined)
2103
2189
  return;
2190
+ retractRecalledCopy(entry.text);
2104
2191
  updateFoldBlock(null);
2105
2192
  restoreDraftImages(entry);
2106
2193
  setInput(entry.text);
@@ -1 +1 @@
1
- {"version":3,"file":"SplitDiffView.d.ts","sourceRoot":"","sources":["../../../src/components/SplitDiffView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAO7D,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AACjE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAA;AAG/E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAwR3D,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,KAAK,EACL,OAAO,EACP,OAAO,EACP,cAAuB,EACvB,MAAM,GACP,EAAE;IACD,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;IACvC,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAA;IACxC;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAC3C,GAAG,KAAK,CAAC,SAAS,CAwFlB"}
1
+ {"version":3,"file":"SplitDiffView.d.ts","sourceRoot":"","sources":["../../../src/components/SplitDiffView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAO7D,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AACjE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAA;AAI/E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAyR3D,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,KAAK,EACL,OAAO,EACP,OAAO,EACP,cAAuB,EACvB,MAAM,GACP,EAAE;IACD,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;IACvC,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAA;IACxC;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAC3C,GAAG,KAAK,CAAC,SAAS,CAwFlB"}
@@ -10,8 +10,10 @@ import { highlightLines, syntaxThemeSignature } from '../terminal-utils/syntaxRu
10
10
  export { chalkFromToken } from '../terminal-utils/syntaxTheme.js';
11
11
  export { parseAnsiRuns, highlightLines } from '../terminal-utils/syntaxRuns.js';
12
12
  import { getTheme } from '../theme.js';
13
+ import { t } from '../i18n.js';
13
14
  import { useTheme } from './design-system/ThemeProvider.js';
14
15
  import { revealLinesOf } from './smoothReveal.js';
16
+ import { primaryComboString } from '../utils/keymap.js';
15
17
  /** Replace tabs so width math and alignment hold (pi convention). */
16
18
  const expandTabs = (text) => text.replaceAll('\t', ' ');
17
19
  /**
@@ -274,5 +276,5 @@ export function SplitDiffView({ diffs, width, maxRows, verbose, toolBackground =
274
276
  ? undefined
275
277
  : { segments: newRuns !== undefined ? mergeRuns(newRuns, row.newWords) : row.newWords };
276
278
  return (_jsxs(Box, { flexDirection: "row", children: [_jsx(PaneLine, { side: oldSide, kind: row.kind === 'add' ? 'context' : row.kind, tone: "old", width: paneWidth, toolBackground: toolBackground }), _jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { dimColor: true, children: "\u2502" }) }), _jsx(PaneLine, { side: newSide, kind: row.kind === 'del' ? 'context' : row.kind, tone: "new", width: paneWidth, toolBackground: toolBackground, padLeft: true })] }, index));
277
- }), hidden > 0 && (_jsx(Text, { dimColor: true, children: `… +${hidden} lines (ctrl+o to expand)` }))] }));
279
+ }), hidden > 0 && (_jsx(Text, { dimColor: true, children: t('lines-folded-expand', { n: hidden, key: primaryComboString('transcript') }) }))] }));
278
280
  }
@@ -0,0 +1,53 @@
1
+ import React from 'react';
2
+ import type { StarMilestone } from '../usageStats.js';
3
+ /** What a star attempt came back with (the modal renders each outcome). */
4
+ export type StarAttempt = {
5
+ readonly kind: 'starred';
6
+ } | {
7
+ readonly kind: 'no-gh';
8
+ readonly url: string;
9
+ } | {
10
+ readonly kind: 'not-authed';
11
+ readonly url: string;
12
+ } | {
13
+ readonly kind: 'failed';
14
+ readonly detail: string;
15
+ readonly url: string;
16
+ };
17
+ /** The two things the modal can do (Chat supplies the real actions; tests
18
+ * override them through the same seam). `onStar` reports the outcome so the
19
+ * modal can celebrate a real star instead of guessing. */
20
+ export interface StarPromptActions {
21
+ onStar: () => StarAttempt | Promise<StarAttempt>;
22
+ onOpen: () => void;
23
+ }
24
+ /**
25
+ * The one-time "asks for a star" startup modal (usage milestones `99h` /
26
+ * `999 launches`, see `usageStats.ts`). Chat mounts it over a dimmed
27
+ * click-catcher on boot when `dueStarModal()` says the moment arrived —
28
+ * never mid-turn, at most one milestone per boot, `Esc`/click-outside
29
+ * closes, and unmounting hands the keyboard straight back (nothing is left
30
+ * registered, so it cannot steal keys after closing).
31
+ *
32
+ * Composition follows the house design system: the milestone title sits in
33
+ * the card's top border, the two actions are `ListItem` rows (pointer,
34
+ * focus colour, hover background — the same component every picker uses),
35
+ * a `Divider` separates the footer, and the hint line is a `HintLine` with
36
+ * its bold key. The art slot shows the raster maid first, the animated
37
+ * pixel whale otherwise.
38
+ *
39
+ * A successful star switches the card into a short CELEBRATION instead of
40
+ * closing silently: confetti falls over the whale, which spouts on a loop,
41
+ * with a thank-you line — then the card closes itself. A failed attempt
42
+ * keeps the card open with the reason and the browser escape hatch.
43
+ */
44
+ export declare function StarPrompt({ milestone, actions, onClose, initialPhase, }: {
45
+ /** The reached milestone (drives the title's hours/launches wording). */
46
+ readonly milestone: StarMilestone;
47
+ readonly actions: StarPromptActions;
48
+ readonly onClose: () => void;
49
+ /** 起始阶段:`done` 直接进庆祝态——`/star`、`Alt+S`、标语点击成功后就
50
+ * 走这条(只演感谢,不再问一次)。 */
51
+ readonly initialPhase?: 'ask' | 'done';
52
+ }): React.ReactNode;
53
+ //# sourceMappingURL=StarPrompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StarPrompt.d.ts","sourceRoot":"","sources":["../../../src/components/StarPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAWzB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAuBrD,2EAA2E;AAC3E,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAC5B;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAA;AAE9E;;0DAE0D;AAC1D,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IAChD,MAAM,EAAE,MAAM,IAAI,CAAA;CACnB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CAAC,EACzB,SAAS,EACT,OAAO,EACP,OAAO,EACP,YAAoB,GACrB,EAAE;IACD,yEAAyE;IACzE,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAA;IACjC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAA;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAA;IAC5B;2BACuB;IACvB,QAAQ,CAAC,YAAY,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;CACvC,GAAG,KAAK,CAAC,SAAS,CAsOlB"}
@@ -0,0 +1,281 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { Box, Text, useInput, useTerminalImages, useTerminalSize } from '../ui.js';
4
+ import { getLang, subscribeLang, t } from '../i18n.js';
5
+ import { Divider } from './design-system/Divider.js';
6
+ import { HintLine } from './design-system/HintLine.js';
7
+ import { ListItem } from './design-system/ListItem.js';
8
+ import { MaidPortrait, useMaidPortraits } from './maidPortrait.js';
9
+ import { useTerminalBackground } from './design-system/ThemeProvider.js';
10
+ import { STANDARD_FRAME_INDEX, WhaleArt } from './Whale.js';
11
+ import { OPENING_SEQUENCES, WHALE_FRAME_INDEX } from './whaleFrames.js';
12
+ /** Art slot width — the pixel whale fallback is 40 columns wide, and the
13
+ * raster portrait fits inside the same slot so the card width never moves. */
14
+ const ART_COLUMNS = 40;
15
+ /** Art slot height: 18 rows (confetti 3 + whale 13 in the celebration), and
16
+ * the text column is pinned to the same height (see the column's comment). */
17
+ const ART_ROWS = 18;
18
+ /** Text column width: every copy line, button and hint stays on ONE row
19
+ * (the "排版不舒适" report: no stranded `⭐`, no mid-sentence breaks). */
20
+ const TEXT_COLUMNS = 48;
21
+ /** Portrait + text side by side need this many columns (art 40 + gap 2 +
22
+ * text 48 + card chrome 6); below that the card drops the art and stacks
23
+ * text at the narrower width. */
24
+ const MIN_ART_COLUMNS = 98;
25
+ /** Card height with the art (18 art rows + 2 border rows); terminals shorter
26
+ * than this + 2 margin rows get the text-only card. */
27
+ const MIN_ART_ROWS = 23;
28
+ /** Dwell on the standard pose before the fallback whale's intro loops. */
29
+ const WHALE_REST_MS = 3000;
30
+ /** How long the celebration stays before the card closes itself. */
31
+ const CELEBRATION_MS = 4200;
32
+ /**
33
+ * The one-time "asks for a star" startup modal (usage milestones `99h` /
34
+ * `999 launches`, see `usageStats.ts`). Chat mounts it over a dimmed
35
+ * click-catcher on boot when `dueStarModal()` says the moment arrived —
36
+ * never mid-turn, at most one milestone per boot, `Esc`/click-outside
37
+ * closes, and unmounting hands the keyboard straight back (nothing is left
38
+ * registered, so it cannot steal keys after closing).
39
+ *
40
+ * Composition follows the house design system: the milestone title sits in
41
+ * the card's top border, the two actions are `ListItem` rows (pointer,
42
+ * focus colour, hover background — the same component every picker uses),
43
+ * a `Divider` separates the footer, and the hint line is a `HintLine` with
44
+ * its bold key. The art slot shows the raster maid first, the animated
45
+ * pixel whale otherwise.
46
+ *
47
+ * A successful star switches the card into a short CELEBRATION instead of
48
+ * closing silently: confetti falls over the whale, which spouts on a loop,
49
+ * with a thank-you line — then the card closes itself. A failed attempt
50
+ * keeps the card open with the reason and the browser escape hatch.
51
+ */
52
+ export function StarPrompt({ milestone, actions, onClose, initialPhase = 'ask', }) {
53
+ React.useSyncExternalStore(subscribeLang, getLang);
54
+ const { columns, rows } = useTerminalSize();
55
+ const imagesAvailable = useTerminalImages();
56
+ const portraits = useMaidPortraits(imagesAvailable);
57
+ const maidSource = portraits?.normal;
58
+ // 卡片底色用**终端真底色**(OSC 11)而不是主题的卡片色:后者是一整块
59
+ // 与终端背景无关的实色板,压在带背景图的终端上很僵硬;用真底色时卡片
60
+ // 与终端同色、只靠边框和暗化的背景区分层次,同时它也是真图立绘的不透明
61
+ // 衬底(Sixel 没有 alpha,透明像素得合成到某个实色上)。
62
+ const terminalBackground = useTerminalBackground();
63
+ const withArt = columns >= MIN_ART_COLUMNS && rows >= MIN_ART_ROWS;
64
+ const [phase, setPhase] = React.useState(initialPhase);
65
+ const [failure, setFailure] = React.useState('');
66
+ const [selected, setSelected] = React.useState(0);
67
+ // Some terminals report one Enter twice (parsed Return then raw CR); the
68
+ // modal must not fire its action twice for one press.
69
+ const lastEnterRef = React.useRef(0);
70
+ const live = React.useRef(true);
71
+ React.useEffect(() => () => { live.current = false; }, []);
72
+ const runStar = () => {
73
+ if (phase === 'working' || phase === 'done')
74
+ return;
75
+ setPhase('working');
76
+ void Promise.resolve(actions.onStar()).then(attempt => {
77
+ if (!live.current)
78
+ return;
79
+ if (attempt.kind === 'starred') {
80
+ setPhase('done');
81
+ return;
82
+ }
83
+ setFailure(attempt.kind === 'failed'
84
+ ? t('star-failed', { detail: attempt.detail, url: attempt.url })
85
+ : t(attempt.kind === 'no-gh' ? 'star-no-gh' : 'star-not-authed', { url: attempt.url }));
86
+ // gh 缺失/未登录这类"本机没法一键"的结局:光标直接落到浏览器那一行,
87
+ // 用户按一下 Enter 就打开浏览器自己去点(不必先按 ↓)。
88
+ if (attempt.kind === 'no-gh' || attempt.kind === 'not-authed')
89
+ setSelected(1);
90
+ setPhase('failed');
91
+ }, (error) => {
92
+ if (!live.current)
93
+ return;
94
+ setFailure(t('star-failed', { detail: String(error), url: '' }));
95
+ setPhase('failed');
96
+ });
97
+ };
98
+ // The celebration bows out on its own; a key press closes it early.
99
+ React.useEffect(() => {
100
+ if (phase !== 'done')
101
+ return;
102
+ const timer = setTimeout(onClose, CELEBRATION_MS);
103
+ return () => { clearTimeout(timer); };
104
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- 只在进入庆祝时起表
105
+ }, [phase]);
106
+ useInput((input, key) => {
107
+ if (phase === 'done') {
108
+ onClose();
109
+ return;
110
+ }
111
+ if (key.escape) {
112
+ onClose();
113
+ return;
114
+ }
115
+ if (key.upArrow || key.downArrow || key.tab) {
116
+ setSelected(previous => (previous + 1) % 2);
117
+ return;
118
+ }
119
+ if (key.return) {
120
+ const now = Date.now();
121
+ if (now - lastEnterRef.current < 50)
122
+ return;
123
+ lastEnterRef.current = now;
124
+ if (selected === 0)
125
+ runStar();
126
+ else
127
+ actions.onOpen();
128
+ }
129
+ });
130
+ const textColumns = withArt ? TEXT_COLUMNS : Math.max(24, Math.min(TEXT_COLUMNS, columns - 6));
131
+ const cardColumns = withArt ? 96 : Math.min(columns, textColumns + 6);
132
+ // 卡片 = 艺术槽 + 上下边框。absolute 卡片的高度上限由**根节点高度**决定:
133
+ // 根只有内容高(内联模式的夹具)时,卡片顶端会被裁掉——夹具因此把 Chat
134
+ // 包在视口大小的 Box 里(真机 alt-screen 的根就是整屏)。
135
+ const cardRows = withArt ? ART_ROWS + 2 : 18;
136
+ const left = Math.max(0, Math.floor((columns - cardColumns) / 2));
137
+ const bottom = Math.max(0, Math.min(Math.floor((rows - cardRows) / 2), rows - cardRows));
138
+ const celebrating = phase === 'done';
139
+ const title = celebrating
140
+ ? t('star-modal-thanks-title')
141
+ : milestone.hours !== undefined
142
+ ? t('star-modal-title-hours', { hours: milestone.hours })
143
+ : t('star-modal-title-launches', { launches: milestone.launches ?? 0 });
144
+ return (_jsxs(_Fragment, { children: [_jsx(Box, { position: "absolute", bottom: 0, left: 0, width: "100%", height: rows, flexShrink: 0, backdrop: "dim", onClick: onClose }), _jsx(Box, { position: "absolute", left: left, bottom: bottom, width: cardColumns, height: cardRows, flexDirection: "column", flexShrink: 0, overflow: "hidden", backgroundColor: terminalBackground, opaque: true, onClick: event => { event.stopImmediatePropagation(); }, children: _jsxs(Box, { flexDirection: "row", gap: 2, alignItems: "center", justifyContent: "center", borderStyle: "round", borderColor: "inactive", paddingX: 2, backgroundColor: terminalBackground, children: [withArt && (_jsx(ArtSlot, { celebrating: celebrating, phase: phase, imagesAvailable: imagesAvailable, maidSource: maidSource, maidHappy: portraits?.happy, background: terminalBackground })), _jsxs(Box, { flexDirection: "column", width: textColumns, ...(withArt ? { height: ART_ROWS } : {}), children: [_jsx(Box, { height: 1, flexShrink: 0, children: _jsx(Text, { color: "accent", bold: true, wrap: "truncate-end", children: title }) }), _jsx(Box, { height: 1 }), celebrating ? (_jsxs(_Fragment, { children: [_jsx(Text, { wrap: "wrap", children: t('star-modal-thanks-1') }), _jsx(Box, { height: 1 }), _jsx(Text, { wrap: "wrap", children: t('star-modal-thanks-2') }), _jsx(Text, { wrap: "wrap", children: t('star-modal-thanks-3') }), _jsx(Text, { wrap: "wrap", children: t('star-modal-thanks-4') }), _jsx(Box, { flexGrow: 1 }), _jsx(Divider, { width: textColumns }), _jsx(Box, { height: 1 }), _jsx(Text, { dimColor: true, wrap: "wrap", children: _jsx(HintLine, { text: t('star-modal-thanks-hint') }) })] })) : (_jsxs(_Fragment, { children: [_jsx(Text, { wrap: "wrap", children: t('star-modal-body-1') }), _jsx(Box, { height: 1 }), _jsx(Text, { wrap: "wrap", children: t('star-modal-body-2') }), _jsx(Text, { wrap: "wrap", children: t('star-modal-body-3') }), _jsx(Text, { wrap: "wrap", children: t('star-modal-body-4') }), _jsx(Text, { wrap: "wrap", children: t('star-modal-body-5') }), _jsx(Text, { wrap: "wrap", children: t('star-modal-body-6') }), _jsx(Box, { height: 1 }), _jsx(ListItem, { isFocused: selected === 0, disabled: phase === 'working', declareCursor: false, onClick: event => {
145
+ event.stopImmediatePropagation();
146
+ setSelected(0);
147
+ runStar();
148
+ }, children: phase === 'working' ? t('star-modal-working') : t('star-modal-star') }), _jsx(ListItem, { isFocused: selected === 1, declareCursor: false, onClick: event => {
149
+ event.stopImmediatePropagation();
150
+ setSelected(1);
151
+ actions.onOpen();
152
+ }, children: t('star-modal-open') }), phase === 'failed' && (_jsxs(_Fragment, { children: [_jsx(Box, { height: 1 }), _jsx(Text, { color: "error", wrap: "wrap", children: failure })] })), phase !== 'failed' && (_jsxs(_Fragment, { children: [_jsx(Box, { height: 1 }), _jsx(Divider, { width: textColumns })] })), _jsx(Box, { height: 1 }), _jsx(Text, { dimColor: true, wrap: "wrap", children: _jsx(HintLine, { text: t('star-modal-hint') }) })] }))] })] }) })] }));
153
+ }
154
+ /**
155
+ * The card's art column: the raster maid first, the animated pixel whale
156
+ * otherwise. While celebrating it shows the **happy maid** (raster→raster in
157
+ * the same pixel canvas, so the swap is a clean erase+draw) under the star
158
+ * field; without image protocols the whale spouts instead — character
159
+ * blocks never take this slot.
160
+ */
161
+ function ArtSlot({ celebrating, phase, imagesAvailable, maidSource, maidHappy, background, }) {
162
+ const raster = imagesAvailable && maidSource !== undefined;
163
+ const frame = useWhaleFrames(celebrating && !raster ? 'celebrate' : raster || phase === 'working' ? 'none' : 'intro');
164
+ if (celebrating && raster) {
165
+ return (_jsxs(Box, { width: ART_COLUMNS, height: ART_ROWS, flexShrink: 0, flexDirection: "column", alignItems: "center", justifyContent: "center", backgroundColor: background, children: [_jsx(Confetti, { width: ART_COLUMNS }), _jsx(MaidPortrait, { source: maidHappy ?? maidSource, maxColumns: ART_COLUMNS, maxRows: ART_ROWS - CONFETTI_ROWS, presentation: "preview" })] }));
166
+ }
167
+ if (celebrating) {
168
+ return (_jsxs(Box, { width: ART_COLUMNS, height: ART_ROWS, flexShrink: 0, flexDirection: "column", alignItems: "center", justifyContent: "center", backgroundColor: background, opaque: true, children: [_jsx(Confetti, { width: ART_COLUMNS }), _jsx(WhaleArt, { frameIndex: frame, width: ART_COLUMNS })] }));
169
+ }
170
+ if (raster) {
171
+ return (_jsx(Box, { width: ART_COLUMNS, height: ART_ROWS, flexShrink: 0, flexDirection: "row", justifyContent: "center", alignItems: "center", children: _jsx(MaidPortrait, { source: maidSource, maxColumns: ART_COLUMNS, maxRows: ART_ROWS, presentation: "preview" }) }));
172
+ }
173
+ return (_jsx(Box, { width: ART_COLUMNS, height: ART_ROWS, flexShrink: 0, flexDirection: "row", justifyContent: "center", alignItems: "center", children: _jsx(WhaleArt, { frameIndex: frame, width: ART_COLUMNS }) }));
174
+ }
175
+ /**
176
+ * Drive the art slot's frame: `intro` loops the classic opener with a rest
177
+ * on the standard pose, `celebrate` loops the water spout (the thank-you
178
+ * animation), `none` parks on the standard pose with no timer at all.
179
+ */
180
+ function useWhaleFrames(mode) {
181
+ const [frame, setFrame] = React.useState(STANDARD_FRAME_INDEX);
182
+ React.useEffect(() => {
183
+ if (mode === 'none') {
184
+ setFrame(STANDARD_FRAME_INDEX);
185
+ return;
186
+ }
187
+ const sequence = mode === 'celebrate' ? CELEBRATION_FRAMES : OPENING_SEQUENCES.classic;
188
+ let step = 0;
189
+ let timer;
190
+ const tick = () => {
191
+ const current = sequence[step] ?? sequence[0];
192
+ setFrame(current.frame);
193
+ const last = step === sequence.length - 1;
194
+ step = (step + 1) % sequence.length;
195
+ const rest = mode === 'celebrate' ? 0 : WHALE_REST_MS;
196
+ timer = setTimeout(tick, last ? (rest || current.ms) : current.ms);
197
+ timer.unref?.();
198
+ };
199
+ tick();
200
+ return () => { if (timer !== undefined)
201
+ clearTimeout(timer); };
202
+ }, [mode]);
203
+ return frame;
204
+ }
205
+ /**
206
+ * The celebration loop, paced instead of frantic: the spout blooms up with
207
+ * easing (130→100ms), falls back slower (110→180ms), rests, then ONE gentle
208
+ * tail wag, then rests again——约 3.2s 一轮,与卡片的关闭时间同量级。
209
+ */
210
+ const CELEBRATION_FRAMES = [
211
+ { frame: WHALE_FRAME_INDEX.spout1, ms: 130 },
212
+ { frame: WHALE_FRAME_INDEX.spout2, ms: 120 },
213
+ { frame: WHALE_FRAME_INDEX.spout3, ms: 110 },
214
+ { frame: WHALE_FRAME_INDEX.spout4, ms: 100 },
215
+ { frame: WHALE_FRAME_INDEX.spout5, ms: 100 },
216
+ { frame: WHALE_FRAME_INDEX.spout6, ms: 110 },
217
+ { frame: WHALE_FRAME_INDEX.spout5, ms: 120 },
218
+ { frame: WHALE_FRAME_INDEX.spout4, ms: 130 },
219
+ { frame: WHALE_FRAME_INDEX.spout3, ms: 150 },
220
+ { frame: WHALE_FRAME_INDEX.spout2, ms: 170 },
221
+ { frame: WHALE_FRAME_INDEX.spout1, ms: 190 },
222
+ { frame: STANDARD_FRAME_INDEX, ms: 620 },
223
+ { frame: WHALE_FRAME_INDEX.tail1, ms: 180 },
224
+ { frame: WHALE_FRAME_INDEX.tail2, ms: 200 },
225
+ { frame: WHALE_FRAME_INDEX.tail3, ms: 200 },
226
+ { frame: WHALE_FRAME_INDEX.tail4, ms: 180 },
227
+ { frame: STANDARD_FRAME_INDEX, ms: 520 },
228
+ ];
229
+ /** 星光两行、稀疏:主星(常亮,金色)+ 闪烁星(各列相位不同,同一帧只有
230
+ * 三分之一亮着)——比随机撒点安静,也比满屏星星精致。 */
231
+ const CONFETTI_GLYPHS = ['✦', '✧'];
232
+ const CONFETTI_COLORS = ['warning', 'accent', 'activity'];
233
+ const CONFETTI_FRAMES = 3;
234
+ const CONFETTI_ROWS = 2;
235
+ /** 每几列一颗主星(常亮)。 */
236
+ const CONFETTI_ANCHOR_STRIDE = 7;
237
+ const CONFETTI = Array.from({ length: CONFETTI_FRAMES }, (_, frameIndex) => Array.from({ length: CONFETTI_ROWS }, (_, row) => {
238
+ const runs = [];
239
+ let current = undefined;
240
+ let buffer = '';
241
+ for (let column = 0; column < ART_COLUMNS; column++) {
242
+ const anchor = column % CONFETTI_ANCHOR_STRIDE === 0;
243
+ // 闪烁星:每列一个固定相位,逐帧轮到自己亮一次(在 3 帧里亮 1 帧)。
244
+ const twinkle = !anchor
245
+ && column % 2 === 0
246
+ && (column / 2 + row) % CONFETTI_FRAMES === frameIndex;
247
+ const glyph = anchor ? CONFETTI_GLYPHS[0] : twinkle ? CONFETTI_GLYPHS[1] : ' ';
248
+ const color = anchor
249
+ ? CONFETTI_COLORS[0]
250
+ : twinkle
251
+ ? (column / 2) % 2 === 0 ? CONFETTI_COLORS[1] : CONFETTI_COLORS[2]
252
+ : undefined;
253
+ if (color !== current) {
254
+ if (buffer !== '')
255
+ runs.push({ text: buffer, color: current });
256
+ buffer = '';
257
+ current = color;
258
+ }
259
+ buffer += glyph;
260
+ }
261
+ if (buffer !== '')
262
+ runs.push({ text: buffer, color: current });
263
+ return runs;
264
+ }));
265
+ /** One confetti band, advancing a frame every 160ms while it is mounted. */
266
+ function Confetti({ width }) {
267
+ const frame = useConfettiFrame();
268
+ const rows = CONFETTI[frame] ?? CONFETTI[0];
269
+ return (_jsx(Box, { flexDirection: "column", flexShrink: 0, width: width, children: rows.map((runs, index) => (_jsx(Text, { wrap: "truncate-end", children: runs.map((run, runIndex) => (_jsx(Text, { color: run.color, children: run.text }, runIndex))) }, index))) }));
270
+ }
271
+ function useConfettiFrame() {
272
+ const [frame, setFrame] = React.useState(0);
273
+ React.useEffect(() => {
274
+ const timer = setInterval(() => {
275
+ setFrame(previous => (previous + 1) % CONFETTI_FRAMES);
276
+ }, 220);
277
+ timer.unref?.();
278
+ return () => { clearInterval(timer); };
279
+ }, []);
280
+ return frame;
281
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"StreamingMarkdown.d.ts","sourceRoot":"","sources":["../../../src/components/StreamingMarkdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAuMzB,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,QAAgB,GACjB,EAAE;IACD,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,GAAG,KAAK,CAAC,SAAS,CAyIlB"}
1
+ {"version":3,"file":"StreamingMarkdown.d.ts","sourceRoot":"","sources":["../../../src/components/StreamingMarkdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAwMzB,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,QAAgB,GACjB,EAAE;IACD,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,GAAG,KAAK,CAAC,SAAS,CA2JlB"}
@@ -2,8 +2,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
3
  import { marked } from 'marked';
4
4
  import Box from '../ink/components/Box.js';
5
- import { formatToken, stripPromptXMLTags } from '../terminal-utils/markdown.js';
5
+ import { configureMarked, formatToken, stripPromptXMLTags } from '../terminal-utils/markdown.js';
6
6
  import { t } from '../i18n.js';
7
+ import { isMathBlockToken, mayBecomeCodeSpan } from '../terminal-utils/math.js';
7
8
  import { isStandaloneToken, Markdown } from './Markdown.js';
8
9
  /**
9
10
  * Renders streaming markdown in sealed groups of completed top-level blocks.
@@ -177,6 +178,9 @@ export function StreamingMarkdown({ children, dimColor = false, }) {
177
178
  const prefixVisibleRef = React.useRef(false);
178
179
  const prefixEndsWithNodeRef = React.useRef(false);
179
180
  const prefixTrailingEmptyTextRef = React.useRef(false);
181
+ // The boundary lex below must see the same tokenizer extensions (math
182
+ // blocks) as the Markdown children, or the two disagree on block edges.
183
+ configureMarked();
180
184
  const stripped = stripPromptXMLTags(children);
181
185
  // Reset if text was replaced (defensive; normally unmount handles this)
182
186
  if (!stripped.startsWith(prefixRef.current)) {
@@ -209,6 +213,19 @@ export function StreamingMarkdown({ children, dimColor = false, }) {
209
213
  while (lastContentIdx >= 0 && tokens[lastContentIdx].type === 'space') {
210
214
  lastContentIdx--;
211
215
  }
216
+ // A block formula after a paragraph with an open backtick run is
217
+ // provisional until a blank line: the run's closer may still arrive and
218
+ // turn both into one code span, so the paragraph stays unsealed.
219
+ let consumed = 0;
220
+ for (let i = 0; i < lastContentIdx; i++) {
221
+ const token = tokens[i];
222
+ if (token.type === 'paragraph' && isMathBlockToken(tokens[i + 1]) &&
223
+ mayBecomeCodeSpan(token.raw, stripped.substring(boundary + consumed + token.raw.length))) {
224
+ lastContentIdx = i;
225
+ break;
226
+ }
227
+ consumed += token.raw.length;
228
+ }
212
229
  let advance = 0;
213
230
  for (let i = 0; i < lastContentIdx; i++) {
214
231
  advance += tokens[i].raw.length;
@@ -249,7 +266,7 @@ export function StreamingMarkdown({ children, dimColor = false, }) {
249
266
  }
250
267
  }
251
268
  if (blocks.definitions) {
252
- return _jsx(Markdown, { dimColor: dimColor, cacheTokens: false, children: stripped });
269
+ return _jsx(Markdown, { dimColor: dimColor, inlineMathImages: false, cacheTokens: false, children: stripped });
253
270
  }
254
271
  const stablePrefix = prefixRef.current;
255
272
  const prefixTail = blocks.tail;
@@ -275,5 +292,5 @@ export function StreamingMarkdown({ children, dimColor = false, }) {
275
292
  // an overlapping empty/duplicate boundary.
276
293
  const hasDistinctSuffix = unstableSuffix !== '' &&
277
294
  (stablePrefix === '' || !unstableSuffix.startsWith(stablePrefix));
278
- return (_jsxs(Box, { flexDirection: "column", children: [blocks.blocks.map((block, index) => (_jsx(Box, { flexDirection: "column", marginTop: block.gap, children: _jsx(Markdown, { dimColor: dimColor, children: block.text }) }, index))), prefixTail && (_jsx(Box, { flexDirection: "column", marginTop: blocks.tailGap, children: _jsx(Markdown, { dimColor: dimColor, children: prefixTail }) }, "prefix")), hasDistinctSuffix && (_jsx(Box, { flexDirection: "column", marginTop: boundaryGap, children: _jsx(Markdown, { dimColor: dimColor, cacheTokens: false, children: unstableSuffix }) }, "suffix"))] }));
295
+ return (_jsxs(Box, { flexDirection: "column", children: [blocks.blocks.map((block, index) => (_jsx(Box, { flexDirection: "column", marginTop: block.gap, children: _jsx(Markdown, { dimColor: dimColor, inlineMathImages: false, children: block.text }) }, index))), prefixTail && (_jsx(Box, { flexDirection: "column", marginTop: blocks.tailGap, children: _jsx(Markdown, { dimColor: dimColor, inlineMathImages: false, children: prefixTail }) }, "prefix")), hasDistinctSuffix && (_jsx(Box, { flexDirection: "column", marginTop: boundaryGap, children: _jsx(Markdown, { dimColor: dimColor, inlineMathImages: false, cacheTokens: false, children: unstableSuffix }) }, "suffix"))] }));
279
296
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SubagentCard.d.ts","sourceRoot":"","sources":["../../../src/components/SubagentCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAEvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAGhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AAO9D,MAAM,WAAW,iBAAiB;IAAG,QAAQ,EAAE,aAAa,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;CAAE;AAEpH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,iBAAiB,GAAG,KAAK,CAAC,SAAS,CA0C/F"}
1
+ {"version":3,"file":"SubagentCard.d.ts","sourceRoot":"","sources":["../../../src/components/SubagentCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAEvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAGhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AAO9D,MAAM,WAAW,iBAAiB;IAAG,QAAQ,EAAE,aAAa,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;CAAE;AAEpH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,iBAAiB,GAAG,KAAK,CAAC,SAAS,CAgD/F"}