@drscrewdriver/dsh-better-display 0.3.3-fork.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 (390) hide show
  1. package/CHANGELOG.md +259 -0
  2. package/DESIGN.md +72 -0
  3. package/LICENSE +24 -0
  4. package/README.en.md +55 -0
  5. package/README.md +55 -0
  6. package/THIRD_PARTY_NOTICES.md +65 -0
  7. package/compat/harness-rc2.json +99 -0
  8. package/cordis.patch.yml +5 -0
  9. package/cordis.yml +4 -0
  10. package/docs/official-rendering-bridge.md +65 -0
  11. package/dshx.yml +5 -0
  12. package/lib/client.js +49292 -0
  13. package/lib/client.js.map +1 -0
  14. package/lib/dsh-better-display.js +101 -0
  15. package/lib/types/client/Blocks.d.ts +49 -0
  16. package/lib/types/client/Blocks.d.ts.map +1 -0
  17. package/lib/types/client/Blocks.js +143 -0
  18. package/lib/types/client/Blocks.js.map +1 -0
  19. package/lib/types/client/ChoreographedFlow.d.ts +22 -0
  20. package/lib/types/client/ChoreographedFlow.d.ts.map +1 -0
  21. package/lib/types/client/ChoreographedFlow.js +218 -0
  22. package/lib/types/client/ChoreographedFlow.js.map +1 -0
  23. package/lib/types/client/ClosedProcessSummary.d.ts +9 -0
  24. package/lib/types/client/ClosedProcessSummary.d.ts.map +1 -0
  25. package/lib/types/client/ClosedProcessSummary.js +16 -0
  26. package/lib/types/client/ClosedProcessSummary.js.map +1 -0
  27. package/lib/types/client/DiffPanel.d.ts +13 -0
  28. package/lib/types/client/DiffPanel.d.ts.map +1 -0
  29. package/lib/types/client/DiffPanel.js +115 -0
  30. package/lib/types/client/DiffPanel.js.map +1 -0
  31. package/lib/types/client/LiveFold.d.ts +10 -0
  32. package/lib/types/client/LiveFold.d.ts.map +1 -0
  33. package/lib/types/client/LiveFold.js +39 -0
  34. package/lib/types/client/LiveFold.js.map +1 -0
  35. package/lib/types/client/McpAppFrame.d.ts +32 -0
  36. package/lib/types/client/McpAppFrame.d.ts.map +1 -0
  37. package/lib/types/client/McpAppFrame.js +193 -0
  38. package/lib/types/client/McpAppFrame.js.map +1 -0
  39. package/lib/types/client/OfficialContent.d.ts +25 -0
  40. package/lib/types/client/OfficialContent.d.ts.map +1 -0
  41. package/lib/types/client/OfficialContent.js +53 -0
  42. package/lib/types/client/OfficialContent.js.map +1 -0
  43. package/lib/types/client/Reader.d.ts +3 -0
  44. package/lib/types/client/Reader.d.ts.map +1 -0
  45. package/lib/types/client/Reader.js +603 -0
  46. package/lib/types/client/Reader.js.map +1 -0
  47. package/lib/types/client/ReasoningCard.d.ts +11 -0
  48. package/lib/types/client/ReasoningCard.d.ts.map +1 -0
  49. package/lib/types/client/ReasoningCard.js +322 -0
  50. package/lib/types/client/ReasoningCard.js.map +1 -0
  51. package/lib/types/client/SettingsSection.d.ts +37 -0
  52. package/lib/types/client/SettingsSection.d.ts.map +1 -0
  53. package/lib/types/client/SettingsSection.js +63 -0
  54. package/lib/types/client/SettingsSection.js.map +1 -0
  55. package/lib/types/client/StickyLane.d.ts +8 -0
  56. package/lib/types/client/StickyLane.d.ts.map +1 -0
  57. package/lib/types/client/StickyLane.js +39 -0
  58. package/lib/types/client/StickyLane.js.map +1 -0
  59. package/lib/types/client/TimelineRail.d.ts +10 -0
  60. package/lib/types/client/TimelineRail.d.ts.map +1 -0
  61. package/lib/types/client/TimelineRail.js +168 -0
  62. package/lib/types/client/TimelineRail.js.map +1 -0
  63. package/lib/types/client/ToolActivity.d.ts +17 -0
  64. package/lib/types/client/ToolActivity.d.ts.map +1 -0
  65. package/lib/types/client/ToolActivity.js +244 -0
  66. package/lib/types/client/ToolActivity.js.map +1 -0
  67. package/lib/types/client/TurnMetrics.d.ts +11 -0
  68. package/lib/types/client/TurnMetrics.d.ts.map +1 -0
  69. package/lib/types/client/TurnMetrics.js +44 -0
  70. package/lib/types/client/TurnMetrics.js.map +1 -0
  71. package/lib/types/client/WaitClock.d.ts +16 -0
  72. package/lib/types/client/WaitClock.d.ts.map +1 -0
  73. package/lib/types/client/WaitClock.js +29 -0
  74. package/lib/types/client/WaitClock.js.map +1 -0
  75. package/lib/types/client/WaitingClock.d.ts +15 -0
  76. package/lib/types/client/WaitingClock.d.ts.map +1 -0
  77. package/lib/types/client/WaitingClock.js +30 -0
  78. package/lib/types/client/WaitingClock.js.map +1 -0
  79. package/lib/types/client/WaitingStatus.d.ts +6 -0
  80. package/lib/types/client/WaitingStatus.d.ts.map +1 -0
  81. package/lib/types/client/WaitingStatus.js +9 -0
  82. package/lib/types/client/WaitingStatus.js.map +1 -0
  83. package/lib/types/client/conversation-scroll.d.ts +19 -0
  84. package/lib/types/client/conversation-scroll.d.ts.map +1 -0
  85. package/lib/types/client/conversation-scroll.js +25 -0
  86. package/lib/types/client/conversation-scroll.js.map +1 -0
  87. package/lib/types/client/deliverables.d.ts +24 -0
  88. package/lib/types/client/deliverables.d.ts.map +1 -0
  89. package/lib/types/client/deliverables.js +104 -0
  90. package/lib/types/client/deliverables.js.map +1 -0
  91. package/lib/types/client/entry-policy.d.ts +10 -0
  92. package/lib/types/client/entry-policy.d.ts.map +1 -0
  93. package/lib/types/client/entry-policy.js +24 -0
  94. package/lib/types/client/entry-policy.js.map +1 -0
  95. package/lib/types/client/entry.d.ts +4 -0
  96. package/lib/types/client/entry.d.ts.map +1 -0
  97. package/lib/types/client/entry.js +34 -0
  98. package/lib/types/client/entry.js.map +1 -0
  99. package/lib/types/client/fold-choreography.d.ts +40 -0
  100. package/lib/types/client/fold-choreography.d.ts.map +1 -0
  101. package/lib/types/client/fold-choreography.js +48 -0
  102. package/lib/types/client/fold-choreography.js.map +1 -0
  103. package/lib/types/client/fold-intensity.d.ts +11 -0
  104. package/lib/types/client/fold-intensity.d.ts.map +1 -0
  105. package/lib/types/client/fold-intensity.js +32 -0
  106. package/lib/types/client/fold-intensity.js.map +1 -0
  107. package/lib/types/client/index.d.ts +7 -0
  108. package/lib/types/client/index.d.ts.map +1 -0
  109. package/lib/types/client/index.js +195 -0
  110. package/lib/types/client/index.js.map +1 -0
  111. package/lib/types/client/live-turn.d.ts +58 -0
  112. package/lib/types/client/live-turn.d.ts.map +1 -0
  113. package/lib/types/client/live-turn.js +190 -0
  114. package/lib/types/client/live-turn.js.map +1 -0
  115. package/lib/types/client/markdown/MarkdownText.d.ts +41 -0
  116. package/lib/types/client/markdown/MarkdownText.d.ts.map +1 -0
  117. package/lib/types/client/markdown/MarkdownText.js +178 -0
  118. package/lib/types/client/markdown/MarkdownText.js.map +1 -0
  119. package/lib/types/client/markdown/cjkFriendlyStrong.d.ts +9 -0
  120. package/lib/types/client/markdown/cjkFriendlyStrong.d.ts.map +1 -0
  121. package/lib/types/client/markdown/cjkFriendlyStrong.js +73 -0
  122. package/lib/types/client/markdown/cjkFriendlyStrong.js.map +1 -0
  123. package/lib/types/client/markdown/incremental.d.ts +69 -0
  124. package/lib/types/client/markdown/incremental.d.ts.map +1 -0
  125. package/lib/types/client/markdown/incremental.js +108 -0
  126. package/lib/types/client/markdown/incremental.js.map +1 -0
  127. package/lib/types/client/markdown/katex.d.ts +27 -0
  128. package/lib/types/client/markdown/katex.d.ts.map +1 -0
  129. package/lib/types/client/markdown/katex.js +88 -0
  130. package/lib/types/client/markdown/katex.js.map +1 -0
  131. package/lib/types/client/markdown/mathCompatibility.d.ts +11 -0
  132. package/lib/types/client/markdown/mathCompatibility.d.ts.map +1 -0
  133. package/lib/types/client/markdown/mathCompatibility.js +293 -0
  134. package/lib/types/client/markdown/mathCompatibility.js.map +1 -0
  135. package/lib/types/client/markdown/parse.d.ts +25 -0
  136. package/lib/types/client/markdown/parse.d.ts.map +1 -0
  137. package/lib/types/client/markdown/parse.js +42 -0
  138. package/lib/types/client/markdown/parse.js.map +1 -0
  139. package/lib/types/client/markdown/render.d.ts +121 -0
  140. package/lib/types/client/markdown/render.d.ts.map +1 -0
  141. package/lib/types/client/markdown/render.js +452 -0
  142. package/lib/types/client/markdown/render.js.map +1 -0
  143. package/lib/types/client/mcp-app.d.ts +50 -0
  144. package/lib/types/client/mcp-app.d.ts.map +1 -0
  145. package/lib/types/client/mcp-app.js +328 -0
  146. package/lib/types/client/mcp-app.js.map +1 -0
  147. package/lib/types/client/message-chrome.d.ts +19 -0
  148. package/lib/types/client/message-chrome.d.ts.map +1 -0
  149. package/lib/types/client/message-chrome.js +42 -0
  150. package/lib/types/client/message-chrome.js.map +1 -0
  151. package/lib/types/client/motion.d.ts +38 -0
  152. package/lib/types/client/motion.d.ts.map +1 -0
  153. package/lib/types/client/motion.js +453 -0
  154. package/lib/types/client/motion.js.map +1 -0
  155. package/lib/types/client/native/ContextBody.d.ts +130 -0
  156. package/lib/types/client/native/ContextBody.d.ts.map +1 -0
  157. package/lib/types/client/native/ContextBody.js +398 -0
  158. package/lib/types/client/native/ContextBody.js.map +1 -0
  159. package/lib/types/client/native/ContextInjectionRow.d.ts +35 -0
  160. package/lib/types/client/native/ContextInjectionRow.d.ts.map +1 -0
  161. package/lib/types/client/native/ContextInjectionRow.js +42 -0
  162. package/lib/types/client/native/ContextInjectionRow.js.map +1 -0
  163. package/lib/types/client/native/ReferenceIcon.d.ts +16 -0
  164. package/lib/types/client/native/ReferenceIcon.d.ts.map +1 -0
  165. package/lib/types/client/native/ReferenceIcon.js +16 -0
  166. package/lib/types/client/native/ReferenceIcon.js.map +1 -0
  167. package/lib/types/client/native/tool-call-model.d.ts +58 -0
  168. package/lib/types/client/native/tool-call-model.d.ts.map +1 -0
  169. package/lib/types/client/native/tool-call-model.js +219 -0
  170. package/lib/types/client/native/tool-call-model.js.map +1 -0
  171. package/lib/types/client/native/tool-update.d.ts +23 -0
  172. package/lib/types/client/native/tool-update.d.ts.map +1 -0
  173. package/lib/types/client/native/tool-update.js +22 -0
  174. package/lib/types/client/native/tool-update.js.map +1 -0
  175. package/lib/types/client/official-slots.d.ts +71 -0
  176. package/lib/types/client/official-slots.d.ts.map +1 -0
  177. package/lib/types/client/official-slots.js +183 -0
  178. package/lib/types/client/official-slots.js.map +1 -0
  179. package/lib/types/client/open-file.d.ts +29 -0
  180. package/lib/types/client/open-file.d.ts.map +1 -0
  181. package/lib/types/client/open-file.js +71 -0
  182. package/lib/types/client/open-file.js.map +1 -0
  183. package/lib/types/client/pending-submission.d.ts +28 -0
  184. package/lib/types/client/pending-submission.d.ts.map +1 -0
  185. package/lib/types/client/pending-submission.js +28 -0
  186. package/lib/types/client/pending-submission.js.map +1 -0
  187. package/lib/types/client/platform-media.d.ts +6 -0
  188. package/lib/types/client/platform-media.d.ts.map +1 -0
  189. package/lib/types/client/platform-media.js +18 -0
  190. package/lib/types/client/platform-media.js.map +1 -0
  191. package/lib/types/client/primitive-labels.d.ts +10 -0
  192. package/lib/types/client/primitive-labels.d.ts.map +1 -0
  193. package/lib/types/client/primitive-labels.js +38 -0
  194. package/lib/types/client/primitive-labels.js.map +1 -0
  195. package/lib/types/client/projection.d.ts +41 -0
  196. package/lib/types/client/projection.d.ts.map +1 -0
  197. package/lib/types/client/projection.js +112 -0
  198. package/lib/types/client/projection.js.map +1 -0
  199. package/lib/types/client/reasoning-follow.d.ts +10 -0
  200. package/lib/types/client/reasoning-follow.d.ts.map +1 -0
  201. package/lib/types/client/reasoning-follow.js +21 -0
  202. package/lib/types/client/reasoning-follow.js.map +1 -0
  203. package/lib/types/client/resource-address.d.ts +3 -0
  204. package/lib/types/client/resource-address.d.ts.map +1 -0
  205. package/lib/types/client/resource-address.js +33 -0
  206. package/lib/types/client/resource-address.js.map +1 -0
  207. package/lib/types/client/settings-copy.d.ts +7 -0
  208. package/lib/types/client/settings-copy.d.ts.map +1 -0
  209. package/lib/types/client/settings-copy.js +53 -0
  210. package/lib/types/client/settings-copy.js.map +1 -0
  211. package/lib/types/client/settings-slots.d.ts +23 -0
  212. package/lib/types/client/settings-slots.d.ts.map +1 -0
  213. package/lib/types/client/settings-slots.js +2 -0
  214. package/lib/types/client/settings-slots.js.map +1 -0
  215. package/lib/types/client/settings.d.ts +4 -0
  216. package/lib/types/client/settings.d.ts.map +1 -0
  217. package/lib/types/client/settings.js +60 -0
  218. package/lib/types/client/settings.js.map +1 -0
  219. package/lib/types/client/skill-status.d.ts +25 -0
  220. package/lib/types/client/skill-status.d.ts.map +1 -0
  221. package/lib/types/client/skill-status.js +44 -0
  222. package/lib/types/client/skill-status.js.map +1 -0
  223. package/lib/types/client/store.d.ts +35 -0
  224. package/lib/types/client/store.d.ts.map +1 -0
  225. package/lib/types/client/store.js +37 -0
  226. package/lib/types/client/store.js.map +1 -0
  227. package/lib/types/client/stream-buffer.d.ts +37 -0
  228. package/lib/types/client/stream-buffer.d.ts.map +1 -0
  229. package/lib/types/client/stream-buffer.js +150 -0
  230. package/lib/types/client/stream-buffer.js.map +1 -0
  231. package/lib/types/client/streaming.d.ts +18 -0
  232. package/lib/types/client/streaming.d.ts.map +1 -0
  233. package/lib/types/client/streaming.js +84 -0
  234. package/lib/types/client/streaming.js.map +1 -0
  235. package/lib/types/client/timeline.d.ts +26 -0
  236. package/lib/types/client/timeline.d.ts.map +1 -0
  237. package/lib/types/client/timeline.js +48 -0
  238. package/lib/types/client/timeline.js.map +1 -0
  239. package/lib/types/client/tool-activity.d.ts +98 -0
  240. package/lib/types/client/tool-activity.d.ts.map +1 -0
  241. package/lib/types/client/tool-activity.js +301 -0
  242. package/lib/types/client/tool-activity.js.map +1 -0
  243. package/lib/types/client/types.d.ts +91 -0
  244. package/lib/types/client/types.d.ts.map +1 -0
  245. package/lib/types/client/types.js +2 -0
  246. package/lib/types/client/types.js.map +1 -0
  247. package/lib/types/client/waiting-clock.d.ts +49 -0
  248. package/lib/types/client/waiting-clock.d.ts.map +1 -0
  249. package/lib/types/client/waiting-clock.js +80 -0
  250. package/lib/types/client/waiting-clock.js.map +1 -0
  251. package/lib/types/client/word-motion.d.ts +16 -0
  252. package/lib/types/client/word-motion.d.ts.map +1 -0
  253. package/lib/types/client/word-motion.js +90 -0
  254. package/lib/types/client/word-motion.js.map +1 -0
  255. package/lib/types/client/word-timeline.d.ts +32 -0
  256. package/lib/types/client/word-timeline.d.ts.map +1 -0
  257. package/lib/types/client/word-timeline.js +119 -0
  258. package/lib/types/client/word-timeline.js.map +1 -0
  259. package/lib/types/dsh-better-display.d.ts +17 -0
  260. package/lib/types/dsh-better-display.d.ts.map +1 -0
  261. package/lib/types/dsh-better-display.js +93 -0
  262. package/lib/types/dsh-better-display.js.map +1 -0
  263. package/lib/types/skill-roots.d.ts +22 -0
  264. package/lib/types/skill-roots.d.ts.map +1 -0
  265. package/lib/types/skill-roots.js +126 -0
  266. package/lib/types/skill-roots.js.map +1 -0
  267. package/lib/types/skill-status.d.ts +36 -0
  268. package/lib/types/skill-status.d.ts.map +1 -0
  269. package/lib/types/skill-status.js +51 -0
  270. package/lib/types/skill-status.js.map +1 -0
  271. package/package.json +133 -0
  272. package/scripts/build-motion-fixture.mjs +26 -0
  273. package/scripts/check-harness-compat.mjs +71 -0
  274. package/scripts/link-harness-dependencies.mjs +54 -0
  275. package/scripts/verify-auto-fold.mjs +114 -0
  276. package/scripts/verify-official-bridge.mjs +121 -0
  277. package/scripts/verify-tool-shimmer.mjs +62 -0
  278. package/skills/generative-mcpapps/SKILL.md +47 -0
  279. package/skills/generative-mcpapps/examples/interactive_quiz.html +153 -0
  280. package/skills/generative-mcpapps/references/html_boilerplate.md +122 -0
  281. package/skills/generative-mcpapps/references/sep1865_protocol.md +54 -0
  282. package/src/client/Blocks.tsx +213 -0
  283. package/src/client/ChoreographedFlow.tsx +232 -0
  284. package/src/client/ClosedProcessSummary.tsx +23 -0
  285. package/src/client/DiffPanel.tsx +124 -0
  286. package/src/client/LiveFold.tsx +43 -0
  287. package/src/client/McpAppFrame.module.css +210 -0
  288. package/src/client/McpAppFrame.tsx +317 -0
  289. package/src/client/OfficialContent.tsx +69 -0
  290. package/src/client/Reader.module.css +692 -0
  291. package/src/client/Reader.tsx +878 -0
  292. package/src/client/ReasoningCard.tsx +306 -0
  293. package/src/client/SettingsSection.module.css +184 -0
  294. package/src/client/SettingsSection.tsx +194 -0
  295. package/src/client/StickyLane.tsx +34 -0
  296. package/src/client/TimelineRail.module.css +170 -0
  297. package/src/client/TimelineRail.tsx +262 -0
  298. package/src/client/ToolActivity.tsx +274 -0
  299. package/src/client/TurnMetrics.module.css +139 -0
  300. package/src/client/TurnMetrics.tsx +160 -0
  301. package/src/client/WaitClock.tsx +33 -0
  302. package/src/client/WaitingStatus.tsx +13 -0
  303. package/src/client/conversation-scroll.ts +28 -0
  304. package/src/client/deliverables.ts +122 -0
  305. package/src/client/entry-policy.ts +20 -0
  306. package/src/client/entry.tsx +40 -0
  307. package/src/client/fold-choreography.ts +55 -0
  308. package/src/client/fold-intensity.ts +36 -0
  309. package/src/client/index.tsx +222 -0
  310. package/src/client/live-turn.ts +198 -0
  311. package/src/client/markdown/MarkdownText.module.css +304 -0
  312. package/src/client/markdown/MarkdownText.tsx +195 -0
  313. package/src/client/markdown/cjkFriendlyStrong.ts +84 -0
  314. package/src/client/markdown/incremental.ts +131 -0
  315. package/src/client/markdown/katex.tsx +91 -0
  316. package/src/client/markdown/mathCompatibility.ts +350 -0
  317. package/src/client/markdown/parse.ts +45 -0
  318. package/src/client/markdown/render.tsx +647 -0
  319. package/src/client/markdown/upstream.json +14 -0
  320. package/src/client/mcp-app.ts +323 -0
  321. package/src/client/message-chrome.ts +47 -0
  322. package/src/client/motion.tsx +410 -0
  323. package/src/client/native/ContextBody.module.css +161 -0
  324. package/src/client/native/ContextBody.tsx +591 -0
  325. package/src/client/native/ContextInjectionRow.module.css +66 -0
  326. package/src/client/native/ContextInjectionRow.tsx +106 -0
  327. package/src/client/native/ReferenceIcon.tsx +35 -0
  328. package/src/client/native/tool-call-model.ts +248 -0
  329. package/src/client/native/tool-update.ts +32 -0
  330. package/src/client/native/upstream.json +41 -0
  331. package/src/client/official-slots.tsx +211 -0
  332. package/src/client/open-file.ts +94 -0
  333. package/src/client/pending-submission.ts +49 -0
  334. package/src/client/platform-media.ts +17 -0
  335. package/src/client/primitive-labels.ts +54 -0
  336. package/src/client/projection.ts +118 -0
  337. package/src/client/reasoning-follow.ts +28 -0
  338. package/src/client/settings-copy.ts +80 -0
  339. package/src/client/settings-slots.ts +20 -0
  340. package/src/client/settings.tsx +73 -0
  341. package/src/client/skill-status.ts +78 -0
  342. package/src/client/store.ts +75 -0
  343. package/src/client/stream-buffer.ts +136 -0
  344. package/src/client/streaming.tsx +70 -0
  345. package/src/client/style.d.ts +4 -0
  346. package/src/client/timeline.ts +77 -0
  347. package/src/client/tool-activity.ts +298 -0
  348. package/src/client/types.ts +89 -0
  349. package/src/client/waiting-clock.ts +83 -0
  350. package/src/client/word-motion.tsx +92 -0
  351. package/src/client/word-timeline.ts +113 -0
  352. package/src/dsh-better-display.ts +108 -0
  353. package/src/skill-roots.ts +138 -0
  354. package/src/skill-status.ts +81 -0
  355. package/tests/browser-auto-fold.tsx +64 -0
  356. package/tests/browser-closed-gap.tsx +20 -0
  357. package/tests/browser-motion.tsx +65 -0
  358. package/tests/browser-official-bridge.tsx +152 -0
  359. package/tests/browser-sticky-lanes.tsx +22 -0
  360. package/tests/browser-waiting-clock.tsx +14 -0
  361. package/tests/chat-flow-hook.test.ts +66 -0
  362. package/tests/cloud-gate.test.ts +34 -0
  363. package/tests/context-tool-update.test.ts +33 -0
  364. package/tests/conversation-scroll.test.ts +47 -0
  365. package/tests/deliverables.test.ts +128 -0
  366. package/tests/entry.test.ts +42 -0
  367. package/tests/fixtures/maid-composer-hide.html +31 -0
  368. package/tests/fold-choreography.test.ts +54 -0
  369. package/tests/fold-intensity.test.ts +94 -0
  370. package/tests/footer-precedence.test.ts +129 -0
  371. package/tests/history-word-regression.test.ts +16 -0
  372. package/tests/live-turn.test.ts +218 -0
  373. package/tests/mcp-apps.test.ts +157 -0
  374. package/tests/message-chrome.test.ts +29 -0
  375. package/tests/official-slots.test.ts +112 -0
  376. package/tests/open-file.test.ts +114 -0
  377. package/tests/pending-submission.test.ts +45 -0
  378. package/tests/platform-media.test.ts +23 -0
  379. package/tests/projection.test.ts +184 -0
  380. package/tests/reasoning-follow.test.ts +34 -0
  381. package/tests/settings-copy.test.ts +63 -0
  382. package/tests/skill-status.test.ts +137 -0
  383. package/tests/stock-install.test.ts +58 -0
  384. package/tests/stream-buffer.test.ts +102 -0
  385. package/tests/timeline.test.ts +59 -0
  386. package/tests/tool-diff.test.ts +57 -0
  387. package/tests/waiting-clock.test.ts +83 -0
  388. package/tests/word-timeline.test.ts +146 -0
  389. package/tsconfig.json +11 -0
  390. package/tsdown.config.ts +51 -0
@@ -0,0 +1,84 @@
1
+ // Adapted from DeepSeek Harness b150a551b8d465e31e418e1b2eaf5e79bbb7d28e (MIT). See THIRD_PARTY_NOTICES.md.
2
+ /** Let asterisk strong emphasis close after punctuation when CJK prose continues without whitespace. */
3
+
4
+ import { attention } from 'micromark-core-commonmark'
5
+ import { unicodePunctuation } from 'micromark-util-character'
6
+ import { classifyCharacter } from 'micromark-util-classify-character'
7
+ import { codes, constants } from 'micromark-util-symbol'
8
+ import type { Construct, Extension, State, Tokenizer } from 'micromark-util-types'
9
+
10
+ const cjkCharacter = new RegExp([
11
+ '\\p{Script_Extensions=Han}',
12
+ '\\p{Script_Extensions=Hiragana}',
13
+ '\\p{Script_Extensions=Katakana}',
14
+ '\\p{Script_Extensions=Hangul}',
15
+ '\\p{Script_Extensions=Bopomofo}',
16
+ ].join('|'), 'u')
17
+
18
+ function isCjkCharacter(code: number | null): boolean {
19
+ return code !== null && code >= 0 && cjkCharacter.test(String.fromCodePoint(code))
20
+ }
21
+
22
+ const tokenizeCjkFriendlyAttention: Tokenizer = function (effects, ok, nok) {
23
+ const configuredAttentionMarkers = this.parser.constructs.attentionMarkers.null
24
+ if (configuredAttentionMarkers === undefined) {
25
+ throw new Error('micromark CommonMark attention markers are unavailable')
26
+ }
27
+ const attentionMarkers = configuredAttentionMarkers
28
+ const previous = this.previous
29
+ const before = classifyCharacter(previous)
30
+ let marker: number | null = codes.eof
31
+
32
+ return start
33
+
34
+ function start(code: number | null): State | undefined {
35
+ /* v8 ignore next -- this text construct is dispatched only for an asterisk. */
36
+ if (code !== codes.asterisk) return nok(code)
37
+ marker = code
38
+ effects.enter('attentionSequence')
39
+ return inside(code)
40
+ }
41
+
42
+ function inside(code: number | null): State | undefined {
43
+ if (code === marker) {
44
+ effects.consume(code)
45
+ return inside
46
+ }
47
+
48
+ const token = effects.exit('attentionSequence')
49
+ const after = classifyCharacter(code)
50
+ const open = !after || (after === constants.characterGroupPunctuation && Boolean(before))
51
+ || attentionMarkers.includes(code)
52
+ const commonMarkClose = !before
53
+ || (before === constants.characterGroupPunctuation && Boolean(after))
54
+ || attentionMarkers.includes(previous)
55
+ const markerCount = token.end.offset - token.start.offset
56
+ const cjkStrongClose = markerCount >= 2
57
+ && unicodePunctuation(previous)
58
+ && isCjkCharacter(code)
59
+ const close = commonMarkClose || cjkStrongClose
60
+
61
+ token._open = open
62
+ token._close = close
63
+ return ok(code)
64
+ }
65
+ }
66
+
67
+ const cjkFriendlyAttention: Construct = {
68
+ name: 'cjkFriendlyAttention',
69
+ resolveAll: attention.resolveAll,
70
+ tokenize: tokenizeCjkFriendlyAttention,
71
+ }
72
+
73
+ const cjkFriendlyStrongExtension: Extension = {
74
+ text: { [codes.asterisk]: cjkFriendlyAttention },
75
+ }
76
+
77
+ /**
78
+ * Extend CommonMark asterisk strong emphasis for punctuation-delimited CJK
79
+ * prose, as a micromark syntax extension for `fromMarkdown`.
80
+ * @returns The micromark syntax extension.
81
+ */
82
+ export function cjkFriendlyStrong(): Extension {
83
+ return cjkFriendlyStrongExtension
84
+ }
@@ -0,0 +1,131 @@
1
+ // Adapted from DeepSeek Harness b150a551b8d465e31e418e1b2eaf5e79bbb7d28e (MIT). See THIRD_PARTY_NOTICES.md.
2
+ /**
3
+ * Incremental block-level markdown parsing for an append-only text stream.
4
+ *
5
+ * Re-parsing the whole accumulated document on every streaming chunk is
6
+ * quadratic in the final reply length. CommonMark block parsing is line-based
7
+ * and appended text can only reshape the parse frontier — the last top-level
8
+ * block (a paragraph becoming a setext heading or a table, a list continuing
9
+ * after a blank line, an unclosed fence swallowing lines) — so earlier blocks
10
+ * are final. This parser therefore freezes all but the trailing
11
+ * {@link UNSTABLE_TAIL_BLOCKS} blocks and re-parses only the source tail
12
+ * behind them: each source region is parsed O(1) times over the stream
13
+ * instead of once per chunk.
14
+ *
15
+ * The freeze boundary comes from the parser's own `position` offsets, never
16
+ * from custom source scanning. The cut sits at the *end offset* of the last
17
+ * frozen block (not the next block's start): a following block's start offset
18
+ * excludes up to three spaces of insignificant leading indentation, which is
19
+ * harmless to drop, but cutting at the previous end also keeps the
20
+ * inter-block blank lines in the tail so the sliced source stays verbatim.
21
+ *
22
+ * Known deviation, shared with any prefix-freeze scheme: micromark resolves
23
+ * reference-style links and footnotes document-wide at parse time, so a
24
+ * reference whose definition lands on the other side of the freeze boundary
25
+ * renders literally until the settled full parse self-heals it.
26
+ */
27
+
28
+ import type { Root, RootContent } from 'mdast'
29
+
30
+ /**
31
+ * Trailing blocks kept unstable. Appended text reshapes at most the last
32
+ * block; the second-to-last is retained as safety margin so a freeze decision
33
+ * never has to reason about the parse frontier.
34
+ */
35
+ const UNSTABLE_TAIL_BLOCKS = 2
36
+
37
+ /** A top-level mdast block plus a render key that is stable across chunks. */
38
+ export interface PositionedBlock {
39
+ /** The parsed block. Positions inside it are relative to its parse slice. */
40
+ readonly node: RootContent
41
+ /**
42
+ * The block's start offset in the full source text. Stable from the frame
43
+ * a block first appears through freezing, so React reconciles rather than
44
+ * remounts when a block crosses the freeze boundary.
45
+ */
46
+ readonly key: number
47
+ }
48
+
49
+ /** One {@link IncrementalMarkdownParser.update} result. */
50
+ export interface IncrementalBlocks {
51
+ /** Blocks that can no longer change; grows monotonically per generation. */
52
+ readonly frozen: readonly PositionedBlock[]
53
+ /** The re-parsed unstable tail (at most {@link UNSTABLE_TAIL_BLOCKS} blocks plus growth). */
54
+ readonly tail: readonly PositionedBlock[]
55
+ /** Bumped whenever non-append input discards the frozen prefix; callers drop caches keyed on it. */
56
+ readonly generation: number
57
+ }
58
+
59
+ /**
60
+ * A block's render key: its absolute source start offset. A position-less
61
+ * node (a grammar is free to omit positions) falls back to a negative
62
+ * list-index key — unique within one update's tail, which is the only place
63
+ * the fallback can occur: freezing requires the cut block's position, so a
64
+ * position-less parse keeps every block in the tail (real grammars always
65
+ * stamp positions and never take this path).
66
+ */
67
+ function blockKey(node: RootContent, base: number, index: number): number {
68
+ const offset = node.position?.start.offset
69
+ return offset === undefined ? -(index + 1) : base + offset
70
+ }
71
+
72
+ /**
73
+ * Append-only incremental parser over a caller-supplied grammar. One instance
74
+ * accumulates one streaming document; non-append input resets it.
75
+ */
76
+ export class IncrementalMarkdownParser {
77
+ private prevText = ''
78
+ private tailStart = 0
79
+ private frozen: PositionedBlock[] = []
80
+ private generation = 0
81
+ private cached: IncrementalBlocks | null = null
82
+
83
+ /** @param parse - Grammar shared with whatever renders the blocks, so boundaries agree. */
84
+ constructor(private readonly parse: (text: string) => Root) {}
85
+
86
+ /**
87
+ * Fold the current accumulated text and return the frozen/tail split.
88
+ * Idempotent for identical input (the previous result is returned as-is),
89
+ * so callers may invoke it from render paths that re-execute.
90
+ * @param text - The full accumulated markdown source.
91
+ * @returns Frozen and tail blocks with stream-stable render keys.
92
+ */
93
+ update(text: string): IncrementalBlocks {
94
+ if (this.cached !== null && text === this.prevText) return this.cached
95
+ // Deliberate O(prefix) memcmp per update: sound divergence detection has
96
+ // to verify the whole retained prefix, and startsWith compares bytes two
97
+ // orders of magnitude faster than parsing them — the cost this class
98
+ // exists to remove. Passing append/reset deltas instead would push
99
+ // append bookkeeping across the session-projection update boundary for a check
100
+ // that stays sub-millisecond at realistic reply sizes.
101
+ if (!text.startsWith(this.prevText)) {
102
+ this.prevText = ''
103
+ this.tailStart = 0
104
+ this.frozen = []
105
+ this.generation += 1
106
+ }
107
+ this.prevText = text
108
+ const base = this.tailStart
109
+ const blocks = this.parse(text.slice(base)).children
110
+ let firstUnstable = Math.max(0, blocks.length - UNSTABLE_TAIL_BLOCKS)
111
+ if (firstUnstable > 0) {
112
+ const cutEnd = blocks[firstUnstable - 1]?.position?.end.offset
113
+ if (cutEnd === undefined) {
114
+ // A grammar that omits positions leaves nothing to cut at; keep the
115
+ // whole parse in the tail rather than guessing a boundary.
116
+ firstUnstable = 0
117
+ } else {
118
+ for (const node of blocks.slice(0, firstUnstable)) {
119
+ this.frozen.push({ node, key: blockKey(node, base, this.frozen.length) })
120
+ }
121
+ this.tailStart = base + cutEnd
122
+ }
123
+ }
124
+ const tail = blocks.slice(firstUnstable).map((node, index) => ({
125
+ node,
126
+ key: blockKey(node, base, index),
127
+ }))
128
+ this.cached = { frozen: [...this.frozen], tail, generation: this.generation }
129
+ return this.cached
130
+ }
131
+ }
@@ -0,0 +1,91 @@
1
+ // Adapted from DeepSeek Harness b150a551b8d465e31e418e1b2eaf5e79bbb7d28e (MIT). See THIRD_PARTY_NOTICES.md.
2
+ /**
3
+ * TeX-to-React via KaTeX, replicating the rehype-katex pipeline this renderer
4
+ * replaced: the same three-arm error chain (strict render, `strict: 'ignore'`
5
+ * retry, error span) and a DOM-identical element tree, so settled math keeps
6
+ * its exact markup. KaTeX emits an HTML string; the browser's own HTML parser
7
+ * (`DOMParser`, applying the spec's SVG/MathML foreign-content attribute
8
+ * adjustments KaTeX output relies on) turns it into a tree this module maps
9
+ * onto React elements — KaTeX output is a static span/MathML/SVG vocabulary
10
+ * with no raw user HTML, the same trust shiki's tree gets in CodeBlock.
11
+ *
12
+ * React 18 has no MathML support, so the `.katex-mathml` subtree's elements
13
+ * land in the HTML namespace — exactly as they did under the replaced
14
+ * hast-util-to-jsx-runtime pipeline. The visual arm is the `.katex-html`
15
+ * span tree; the MathML arm serves assistive technology, which reads it by
16
+ * tag name regardless of namespace.
17
+ */
18
+
19
+ import { createElement } from 'react'
20
+ import type { CSSProperties, ReactNode } from 'react'
21
+ import katex from 'katex'
22
+
23
+ /**
24
+ * Convert one inline `style` attribute string into React's style object.
25
+ * KaTeX emits only plain kebab-case declarations (no custom properties and no
26
+ * nameless declarations), so camel-casing the property is the whole mapping.
27
+ */
28
+ function styleObject(css: string): CSSProperties {
29
+ const style: Record<string, string> = {}
30
+ for (const declaration of css.split(';')) {
31
+ const colon = declaration.indexOf(':')
32
+ if (colon === -1) continue
33
+ const name = declaration.slice(0, colon).trim()
34
+ const key = name.replace(/-([a-z])/g, (_, letter: string) => letter.toUpperCase())
35
+ style[key] = declaration.slice(colon + 1).trim()
36
+ }
37
+ return style
38
+ }
39
+
40
+ /** Map one parsed DOM node onto a React element (text nodes pass through). */
41
+ function domToReact(node: ChildNode, key: number): ReactNode {
42
+ if (node.nodeType === Node.TEXT_NODE) return node.textContent
43
+ /* v8 ignore next 2 -- KaTeX output holds only elements and text; other
44
+ node kinds cannot appear in its serialized vocabulary. */
45
+ if (node.nodeType !== Node.ELEMENT_NODE) return null
46
+ const element = node as Element
47
+ const props: Record<string, unknown> = { key }
48
+ for (const attribute of element.attributes) {
49
+ if (attribute.name === 'class') props['className'] = attribute.value
50
+ else if (attribute.name === 'style') props['style'] = styleObject(attribute.value)
51
+ else props[attribute.name] = attribute.value
52
+ }
53
+ const children = [...element.childNodes].map(domToReact)
54
+ return children.length === 0
55
+ ? createElement(element.localName, props)
56
+ : createElement(element.localName, props, ...children)
57
+ }
58
+
59
+ /**
60
+ * Render TeX source to React elements through KaTeX.
61
+ * @param value - The TeX source (math node value; fenced `math` blocks append
62
+ * their trailing newline to match the replaced pipeline's text extraction).
63
+ * @param displayMode - Display (block) versus inline rendering.
64
+ * @returns KaTeX's element tree, or the error span when the source does not
65
+ * parse (colored with KaTeX's stock `errorColor`, matching rehype-katex).
66
+ */
67
+ export function renderTexToReact(value: string, displayMode: boolean): ReactNode {
68
+ let html: string
69
+ try {
70
+ html = katex.renderToString(value, { displayMode, throwOnError: true })
71
+ } catch (error) {
72
+ try {
73
+ html = katex.renderToString(value, { displayMode, strict: 'ignore', throwOnError: false })
74
+ } catch {
75
+ // KaTeX renders ParseErrors itself under throwOnError: false; only its
76
+ // internal errors reach here, so mirror rehype-katex's manual span.
77
+ /* v8 ignore next 8 */
78
+ return (
79
+ <span
80
+ className="katex-error"
81
+ style={{ color: '#cc0000' }}
82
+ title={String(error)}
83
+ >
84
+ {value}
85
+ </span>
86
+ )
87
+ }
88
+ }
89
+ const parsed = new DOMParser().parseFromString(html, 'text/html')
90
+ return [...parsed.body.childNodes].map(domToReact)
91
+ }
@@ -0,0 +1,350 @@
1
+ // Adapted from DeepSeek Harness b150a551b8d465e31e418e1b2eaf5e79bbb7d28e (MIT). See THIRD_PARTY_NOTICES.md.
2
+ /** Extend upstream dollar-only math syntax with TeX delimiters while reusing its token vocabulary. */
3
+
4
+ import { factorySpace } from 'micromark-factory-space'
5
+ import type {} from 'micromark-extension-math'
6
+ import { markdownLineEnding } from 'micromark-util-character'
7
+ import { codes, constants, types } from 'micromark-util-symbol'
8
+ import type { Construct, Extension, Previous, State, Tokenizer } from 'micromark-util-types'
9
+
10
+ // oxlint-disable typescript/no-this-alias -- micromark binds tokenizer context only on the outer callback.
11
+
12
+ const previousBackslash: Previous = function (code) {
13
+ if (code !== codes.backslash) return true
14
+ const tail = this.events.at(-1)
15
+ /* v8 ignore next -- a previous code necessarily has a preceding event. */
16
+ if (tail === undefined) return false
17
+ return tail[1].type === types.characterEscape
18
+ }
19
+
20
+ const tokenizeBackslashMathText: Tokenizer = function (effects, ok, nok) {
21
+ return start
22
+
23
+ function start(code: number | null): State | undefined {
24
+ /* v8 ignore next -- the text construct is dispatched only for a backslash. */
25
+ if (code !== codes.backslash) return nok(code)
26
+ effects.enter('mathText')
27
+ effects.enter('mathTextSequence')
28
+ effects.consume(code)
29
+ return open
30
+ }
31
+
32
+ function open(code: number | null): State | undefined {
33
+ if (code !== codes.leftParenthesis) return nok(code)
34
+ effects.consume(code)
35
+ effects.exit('mathTextSequence')
36
+ return between
37
+ }
38
+
39
+ function between(code: number | null): State | undefined {
40
+ if (code === codes.eof) return nok(code)
41
+ if (code === codes.backslash) {
42
+ return effects.attempt({ partial: true, tokenize: tokenizeClose }, close, afterCloseAttempt)(code)
43
+ }
44
+ if (markdownLineEnding(code)) {
45
+ effects.enter(types.lineEnding)
46
+ effects.consume(code)
47
+ effects.exit(types.lineEnding)
48
+ return between
49
+ }
50
+ return dataStart(code)
51
+ }
52
+
53
+ function afterCloseAttempt(code: number | null): State | undefined {
54
+ return effects.check({ partial: true, tokenize: tokenizeOpen }, nok, dataStart)(code)
55
+ }
56
+
57
+ function dataStart(code: number | null): State | undefined {
58
+ effects.enter('mathTextData')
59
+ effects.consume(code)
60
+ return code === codes.backslash ? afterDataBackslash : data
61
+ }
62
+
63
+ function afterDataBackslash(code: number | null): State | undefined {
64
+ if (code === codes.backslash) {
65
+ effects.consume(code)
66
+ return data
67
+ }
68
+ return data(code)
69
+ }
70
+
71
+ function data(code: number | null): State | undefined {
72
+ if (code === codes.eof || code === codes.backslash || markdownLineEnding(code)) {
73
+ effects.exit('mathTextData')
74
+ return between(code)
75
+ }
76
+ effects.consume(code)
77
+ return data
78
+ }
79
+
80
+ function close(code: number | null): State | undefined {
81
+ effects.exit('mathText')
82
+ return ok(code)
83
+ }
84
+
85
+ function tokenizeClose(closeEffects: Parameters<Tokenizer>[0], closeOk: State, closeNok: State): State {
86
+ return slash
87
+
88
+ function slash(code: number | null): State | undefined {
89
+ /* v8 ignore next -- this partial construct is attempted only at a backslash. */
90
+ if (code !== codes.backslash) return closeNok(code)
91
+ closeEffects.enter('mathTextSequence')
92
+ closeEffects.consume(code)
93
+ return parenthesis
94
+ }
95
+
96
+ function parenthesis(code: number | null): State | undefined {
97
+ if (code !== codes.rightParenthesis) return closeNok(code)
98
+ closeEffects.consume(code)
99
+ closeEffects.exit('mathTextSequence')
100
+ return closeOk
101
+ }
102
+ }
103
+
104
+ function tokenizeOpen(openEffects: Parameters<Tokenizer>[0], openOk: State, openNok: State): State {
105
+ return slash
106
+
107
+ function slash(code: number | null): State | undefined {
108
+ /* v8 ignore next -- the opening check follows a failed close attempt at a backslash. */
109
+ if (code !== codes.backslash) return openNok(code)
110
+ openEffects.enter(types.chunkString)
111
+ openEffects.consume(code)
112
+ return parenthesis
113
+ }
114
+
115
+ function parenthesis(code: number | null): State | undefined {
116
+ if (code !== codes.leftParenthesis) return openNok(code)
117
+ openEffects.consume(code)
118
+ openEffects.exit(types.chunkString)
119
+ return openOk
120
+ }
121
+ }
122
+ }
123
+
124
+ function createMathFlow(marker: number, openMarker: number, closeMarker: number, multiline: boolean): Construct {
125
+ const tokenize: Tokenizer = function (effects, ok, nok) {
126
+ const self = this
127
+ let oddBackslashRun = false
128
+ const tail = self.events.at(-1)
129
+ const initialSize = tail?.[1].type === types.linePrefix
130
+ ? tail[2].sliceSerialize(tail[1], true).length
131
+ : 0
132
+
133
+ return start
134
+
135
+ function start(code: number | null): State | undefined {
136
+ /* v8 ignore next -- the flow construct is dispatched only for its marker. */
137
+ if (code !== marker) return nok(code)
138
+ effects.enter('mathFlow')
139
+ effects.enter('mathFlowFence')
140
+ effects.enter('mathFlowFenceSequence')
141
+ effects.consume(code)
142
+ return open
143
+ }
144
+
145
+ function open(code: number | null): State | undefined {
146
+ if (code !== openMarker) return nok(code)
147
+ effects.consume(code)
148
+ effects.exit('mathFlowFenceSequence')
149
+ effects.exit('mathFlowFence')
150
+ return marker === codes.dollarSign ? afterDollarOpen : content
151
+ }
152
+
153
+ function afterDollarOpen(code: number | null): State | undefined {
154
+ return code === codes.dollarSign ? nok(code) : content(code)
155
+ }
156
+
157
+ function content(code: number | null): State | undefined {
158
+ if (code === codes.eof) return nok(code)
159
+ if (code === marker && (marker !== codes.dollarSign || !oddBackslashRun)) {
160
+ return effects.attempt(
161
+ { partial: true, tokenize: tokenizeClosingFence },
162
+ closed,
163
+ afterClosingFenceAttempt,
164
+ )(code)
165
+ }
166
+ if (markdownLineEnding(code)) {
167
+ return multiline
168
+ ? effects.attempt(nonLazyContinuation, afterContinuation, nok)(code)
169
+ : nok(code)
170
+ }
171
+ return valueStart(code)
172
+ }
173
+
174
+ function afterClosingFenceAttempt(code: number | null): State | undefined {
175
+ return marker === codes.backslash
176
+ ? effects.check({ partial: true, tokenize: tokenizeOpeningFence }, nok, markerValueStart)(code)
177
+ : markerValueStart(code)
178
+ }
179
+
180
+ function afterContinuation(code: number | null): State | undefined {
181
+ return effects.attempt(
182
+ { partial: true, tokenize: tokenizeClosingFence },
183
+ closed,
184
+ initialSize
185
+ ? factorySpace(effects, content, types.linePrefix, initialSize + 1)
186
+ : content,
187
+ )(code)
188
+ }
189
+
190
+ function valueStart(code: number | null): State | undefined {
191
+ effects.enter('mathFlowValue')
192
+ oddBackslashRun = code === codes.backslash
193
+ effects.consume(code)
194
+ return value
195
+ }
196
+
197
+ function markerValueStart(code: number | null): State | undefined {
198
+ effects.enter('mathFlowValue')
199
+ oddBackslashRun = false
200
+ effects.consume(code)
201
+ return valueAfterMarker
202
+ }
203
+
204
+ function valueAfterMarker(code: number | null): State | undefined {
205
+ if (code === marker) {
206
+ effects.consume(code)
207
+ return value
208
+ }
209
+ return value(code)
210
+ }
211
+
212
+ function value(code: number | null): State | undefined {
213
+ if (code === codes.eof || code === marker || markdownLineEnding(code)) {
214
+ effects.exit('mathFlowValue')
215
+ return content(code)
216
+ }
217
+ oddBackslashRun = code === codes.backslash ? !oddBackslashRun : false
218
+ effects.consume(code)
219
+ return value
220
+ }
221
+
222
+ function closed(code: number | null): State | undefined {
223
+ effects.exit('mathFlow')
224
+ return ok(code)
225
+ }
226
+
227
+ function tokenizeClosingFence(
228
+ closeEffects: Parameters<Tokenizer>[0],
229
+ closeOk: State,
230
+ closeNok: State,
231
+ ): State {
232
+ return factorySpace(closeEffects, sequenceStart, types.linePrefix, constants.tabSize)
233
+
234
+ function sequenceStart(code: number | null): State | undefined {
235
+ if (code !== marker) return closeNok(code)
236
+ closeEffects.enter('mathFlowFence')
237
+ closeEffects.enter('mathFlowFenceSequence')
238
+ closeEffects.consume(code)
239
+ return sequenceEnd
240
+ }
241
+
242
+ function sequenceEnd(code: number | null): State | undefined {
243
+ if (code !== closeMarker) return closeNok(code)
244
+ closeEffects.consume(code)
245
+ closeEffects.exit('mathFlowFenceSequence')
246
+ return factorySpace(closeEffects, after, types.whitespace)
247
+ }
248
+
249
+ function after(code: number | null): State | undefined {
250
+ if (code !== codes.eof && !markdownLineEnding(code)) return closeNok(code)
251
+ closeEffects.exit('mathFlowFence')
252
+ return closeOk(code)
253
+ }
254
+ }
255
+
256
+ function tokenizeOpeningFence(
257
+ openEffects: Parameters<Tokenizer>[0],
258
+ openOk: State,
259
+ openNok: State,
260
+ ): State {
261
+ return sequenceStart
262
+
263
+ function sequenceStart(code: number | null): State | undefined {
264
+ /* v8 ignore next -- the opening check follows a failed close attempt at the marker. */
265
+ if (code !== marker) return openNok(code)
266
+ openEffects.enter(types.chunkString)
267
+ openEffects.consume(code)
268
+ return sequenceEnd
269
+ }
270
+
271
+ function sequenceEnd(code: number | null): State | undefined {
272
+ if (code !== openMarker) return openNok(code)
273
+ openEffects.consume(code)
274
+ openEffects.exit(types.chunkString)
275
+ return openOk
276
+ }
277
+ }
278
+ }
279
+
280
+ return {
281
+ concrete: true,
282
+ name: marker === codes.dollarSign ? 'sameLineDollarMathFlow' : 'backslashMathFlow',
283
+ tokenize,
284
+ }
285
+ }
286
+
287
+ const tokenizeNonLazyContinuation: Tokenizer = function (effects, ok, nok) {
288
+ const self = this
289
+
290
+ return start
291
+
292
+ function start(code: number | null): State | undefined {
293
+ /* v8 ignore next -- continuation constructs are attempted only after a line ending. */
294
+ if (code === codes.eof) return ok(code)
295
+ /* v8 ignore next -- continuation constructs are attempted only after a line ending. */
296
+ if (!markdownLineEnding(code)) return nok(code)
297
+ effects.enter(types.lineEnding)
298
+ effects.consume(code)
299
+ effects.exit(types.lineEnding)
300
+ return lineStart
301
+ }
302
+
303
+ function lineStart(code: number | null): State | undefined {
304
+ return self.parser.lazy[self.now().line] ? nok(code) : ok(code)
305
+ }
306
+ }
307
+
308
+ const nonLazyContinuation: Construct = {
309
+ partial: true,
310
+ tokenize: tokenizeNonLazyContinuation,
311
+ }
312
+
313
+ const backslashMathText: Construct = {
314
+ name: 'backslashMathText',
315
+ previous: previousBackslash,
316
+ tokenize: tokenizeBackslashMathText,
317
+ }
318
+
319
+ const backslashMathFlow = createMathFlow(
320
+ codes.backslash,
321
+ codes.leftSquareBracket,
322
+ codes.rightSquareBracket,
323
+ true,
324
+ )
325
+
326
+ const sameLineDollarMathFlow = createMathFlow(
327
+ codes.dollarSign,
328
+ codes.dollarSign,
329
+ codes.dollarSign,
330
+ false,
331
+ )
332
+
333
+ const backslashMath: Extension = {
334
+ flow: {
335
+ [codes.backslash]: backslashMathFlow,
336
+ [codes.dollarSign]: sameLineDollarMathFlow,
337
+ },
338
+ text: { [codes.backslash]: backslashMathText },
339
+ }
340
+
341
+ /**
342
+ * TeX backslash delimiters and same-line display-dollar blocks as a micromark
343
+ * syntax extension reusing `micromark-extension-math`'s token vocabulary; the
344
+ * caller must also register `math()` on the same parse so the emitted tokens
345
+ * compile to standard math nodes.
346
+ * @returns The micromark syntax extension.
347
+ */
348
+ export function mathCompatibility(): Extension {
349
+ return backslashMath
350
+ }