@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,126 @@
1
+ import { access, readdir } from 'node:fs/promises';
2
+ import { existsSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { dirname, isAbsolute, join, resolve } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { GENERATIVE_MCPAPPS_SKILL, skillListIncludes, skillRootEntryMatches, } from './skill-status.js';
7
+ export function expandHomePath(path, home = homedir()) {
8
+ if (path === '~')
9
+ return home;
10
+ if (path.startsWith('~/') || path.startsWith('~\\'))
11
+ return join(home, path.slice(2));
12
+ return path;
13
+ }
14
+ /** `$DSH_HOME` or `~/.dsh`, matching official `resolveDshHome`. */
15
+ export function resolveDshHome(env = process.env, home = homedir()) {
16
+ const fromEnv = env.DSH_HOME;
17
+ const selected = fromEnv !== undefined && fromEnv.trim().length > 0 ? fromEnv : join(home, '.dsh');
18
+ return resolve(expandHomePath(selected, home));
19
+ }
20
+ /** `$DSH_AGENTS_HOME` or `~/.agents`. */
21
+ export function resolveAgentsHome(env = process.env, home = homedir()) {
22
+ const fromEnv = env.DSH_AGENTS_HOME;
23
+ const selected = fromEnv !== undefined && fromEnv.trim().length > 0 ? fromEnv : join(home, '.agents');
24
+ return resolve(expandHomePath(selected, home));
25
+ }
26
+ export function userSkillRoots(env = process.env, home = homedir()) {
27
+ return [
28
+ { source: 'user-dsh', path: join(resolveDshHome(env, home), 'skills') },
29
+ { source: 'user-agents', path: join(resolveAgentsHome(env, home), 'skills') },
30
+ ];
31
+ }
32
+ export function projectSkillRoots(projectRoot) {
33
+ return [
34
+ { source: 'project-dsh', path: join(projectRoot, '.dsh', 'skills') },
35
+ { source: 'project-agents', path: join(projectRoot, '.agents', 'skills') },
36
+ ];
37
+ }
38
+ export async function findProjectRoot(cwd) {
39
+ let current = resolve(cwd);
40
+ while (true) {
41
+ if (existsSync(join(current, '.git')))
42
+ return current;
43
+ const parent = dirname(current);
44
+ if (parent === current)
45
+ return resolve(cwd);
46
+ current = parent;
47
+ }
48
+ }
49
+ export async function rootHasGenerativeMcpapps(rootPath) {
50
+ let entries;
51
+ try {
52
+ entries = await readdir(rootPath, { withFileTypes: true });
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ for (const entry of entries) {
58
+ if (entry.name === '.system')
59
+ continue;
60
+ if (!skillRootEntryMatches(entry.name))
61
+ continue;
62
+ if (entry.isDirectory()) {
63
+ try {
64
+ await access(join(rootPath, entry.name, 'SKILL.md'));
65
+ return true;
66
+ }
67
+ catch {
68
+ continue;
69
+ }
70
+ }
71
+ if (entry.isFile())
72
+ return true;
73
+ }
74
+ return false;
75
+ }
76
+ /** Resolve the plugin-shipped pack. This path is never treated as a skill root. */
77
+ export function pluginSkillPackPath(moduleUrl = import.meta.url) {
78
+ const here = dirname(fileURLToPath(moduleUrl));
79
+ const candidates = [
80
+ join(here, '../skills', GENERATIVE_MCPAPPS_SKILL),
81
+ join(here, '../../skills', GENERATIVE_MCPAPPS_SKILL),
82
+ join(here, 'skills', GENERATIVE_MCPAPPS_SKILL),
83
+ ];
84
+ return candidates.find(path => existsSync(join(path, 'SKILL.md')));
85
+ }
86
+ export async function scanGenerativeMcpappsStatus(options = {}) {
87
+ const env = options.env ?? process.env;
88
+ const home = options.home ?? homedir();
89
+ const roots = [...userSkillRoots(env, home)];
90
+ const cwd = typeof options.cwd === 'string' && options.cwd.trim().length > 0
91
+ ? (isAbsolute(options.cwd) ? options.cwd : resolve(options.cwd))
92
+ : undefined;
93
+ if (cwd !== undefined)
94
+ roots.unshift(...projectSkillRoots(await findProjectRoot(cwd)));
95
+ const inspected = [];
96
+ let rootHit = false;
97
+ for (const root of roots) {
98
+ const present = await rootHasGenerativeMcpapps(root.path);
99
+ inspected.push({ ...root, present });
100
+ if (present)
101
+ rootHit = true;
102
+ }
103
+ let via = null;
104
+ let listHit = false;
105
+ if (options.listSkills) {
106
+ try {
107
+ listHit = skillListIncludes(await options.listSkills());
108
+ if (listHit)
109
+ via = 'skills.list';
110
+ }
111
+ catch {
112
+ // Registry/RPC absence falls back to the scanned roots.
113
+ }
114
+ }
115
+ if (!listHit && rootHit)
116
+ via = 'skill-root';
117
+ const packPath = options.packPath ?? pluginSkillPackPath();
118
+ return {
119
+ name: GENERATIVE_MCPAPPS_SKILL,
120
+ installed: listHit || rootHit,
121
+ via,
122
+ roots: inspected,
123
+ ...packPath !== undefined ? { packPath } : {},
124
+ };
125
+ }
126
+ //# sourceMappingURL=skill-roots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-roots.js","sourceRoot":"","sources":["../../src/skill-roots.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /** Shared generative-mcpapps identity. Plugin-tree presence is not installation. */
2
+ export declare const GENERATIVE_MCPAPPS_SKILL = "generative-mcpapps";
3
+ /** Conventional relative roots only. Never expand $HOME or dump host `root.path`. */
4
+ export declare const CONVENTIONAL_SKILL_ROOTS: readonly [".dsh/skills", ".agents/skills"];
5
+ /** Copy source relative to the plugin / checkout, not an absolute pack path. */
6
+ export declare const SKILL_PACK_RELATIVE = "skills/generative-mcpapps";
7
+ export type SkillRootSource = 'project-dsh' | 'project-agents' | 'user-dsh' | 'user-agents' | 'custom' | 'bundled' | (string & {});
8
+ export interface SkillRootInfo {
9
+ readonly source: SkillRootSource;
10
+ readonly path: string;
11
+ readonly present?: boolean;
12
+ }
13
+ export interface HostSkillStatus {
14
+ readonly name: typeof GENERATIVE_MCPAPPS_SKILL;
15
+ readonly installed: boolean;
16
+ readonly via: 'skills.list' | 'skill-root' | null;
17
+ readonly roots: readonly SkillRootInfo[];
18
+ /** Plugin-shipped pack path for copy guidance. Not a harness skill root. */
19
+ readonly packPath?: string;
20
+ }
21
+ export declare function skillNameMatches(name: unknown): boolean;
22
+ export declare function skillListIncludes(entries: readonly {
23
+ readonly name?: string;
24
+ }[] | undefined): boolean;
25
+ /** Directory bundle `name/SKILL.md` or flat `name.md` at a scanned root. */
26
+ export declare function skillRootEntryMatches(entryName: string): boolean;
27
+ export declare function skillsFromListResult(result: unknown): {
28
+ name?: string;
29
+ }[];
30
+ export declare function publicSkillRoots(): readonly SkillRootInfo[];
31
+ /**
32
+ * Strip host home / pack absolutes before anything user-facing (HTTP or Settings).
33
+ * Detection still uses the raw scan; this is the public face.
34
+ */
35
+ export declare function toPublicSkillStatus(status: HostSkillStatus): HostSkillStatus;
36
+ //# sourceMappingURL=skill-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-status.d.ts","sourceRoot":"","sources":["../../src/skill-status.ts"],"names":[],"mappings":"AAAA,oFAAoF;AAEpF,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAE7D,qFAAqF;AACrF,eAAO,MAAM,wBAAwB,4CAA6C,CAAC;AAEnF,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,8BAAuC,CAAC;AAExE,MAAM,MAAM,eAAe,GACvB,aAAa,GACb,gBAAgB,GAChB,UAAU,GACV,aAAa,GACb,QAAQ,GACR,SAAS,GACT,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,OAAO,wBAAwB,CAAC;IAC/C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,aAAa,GAAG,YAAY,GAAG,IAAI,CAAC;IAClD,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAEvD;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,SAAS;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,SAAS,GAAG,OAAO,CAErG;AAED,4EAA4E;AAC5E,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAEhE;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,CAgBzE;AAED,wBAAgB,gBAAgB,IAAI,SAAS,aAAa,EAAE,CAE3D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,eAAe,CAO5E"}
@@ -0,0 +1,51 @@
1
+ /** Shared generative-mcpapps identity. Plugin-tree presence is not installation. */
2
+ export const GENERATIVE_MCPAPPS_SKILL = 'generative-mcpapps';
3
+ /** Conventional relative roots only. Never expand $HOME or dump host `root.path`. */
4
+ export const CONVENTIONAL_SKILL_ROOTS = ['.dsh/skills', '.agents/skills'];
5
+ /** Copy source relative to the plugin / checkout, not an absolute pack path. */
6
+ export const SKILL_PACK_RELATIVE = `skills/${GENERATIVE_MCPAPPS_SKILL}`;
7
+ export function skillNameMatches(name) {
8
+ return typeof name === 'string' && name === GENERATIVE_MCPAPPS_SKILL;
9
+ }
10
+ export function skillListIncludes(entries) {
11
+ return Array.isArray(entries) && entries.some(entry => skillNameMatches(entry?.name));
12
+ }
13
+ /** Directory bundle `name/SKILL.md` or flat `name.md` at a scanned root. */
14
+ export function skillRootEntryMatches(entryName) {
15
+ return entryName === GENERATIVE_MCPAPPS_SKILL || entryName === `${GENERATIVE_MCPAPPS_SKILL}.md`;
16
+ }
17
+ export function skillsFromListResult(result) {
18
+ if (Array.isArray(result))
19
+ return result;
20
+ if (result === null || typeof result !== 'object')
21
+ return [];
22
+ const record = result;
23
+ if (record.ok === false)
24
+ return [];
25
+ if (Array.isArray(record.skills))
26
+ return record.skills;
27
+ if (record.value && typeof record.value === 'object') {
28
+ const value = record.value;
29
+ if (Array.isArray(value.skills))
30
+ return value.skills;
31
+ if (Array.isArray(record.value))
32
+ return record.value;
33
+ }
34
+ return [];
35
+ }
36
+ export function publicSkillRoots() {
37
+ return CONVENTIONAL_SKILL_ROOTS.map(path => ({ source: 'conventional', path }));
38
+ }
39
+ /**
40
+ * Strip host home / pack absolutes before anything user-facing (HTTP or Settings).
41
+ * Detection still uses the raw scan; this is the public face.
42
+ */
43
+ export function toPublicSkillStatus(status) {
44
+ return {
45
+ name: status.name,
46
+ installed: status.installed,
47
+ via: status.via,
48
+ roots: publicSkillRoots(),
49
+ };
50
+ }
51
+ //# sourceMappingURL=skill-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-status.js","sourceRoot":"","sources":["../../src/skill-status.ts"],"names":[],"mappings":"AAAA,oFAAoF;AAEpF,MAAM,CAAC,MAAM,wBAAwB,GAAG,oBAAoB,CAAC;AAE7D,qFAAqF;AACrF,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,aAAa,EAAE,gBAAgB,CAAU,CAAC;AAEnF,gFAAgF;AAChF,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,wBAAwB,EAAE,CAAC;AA0BxE,MAAM,UAAU,gBAAgB,CAAC,IAAa;IAC5C,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,wBAAwB,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAA0D;IAC1F,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;AACxF,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,qBAAqB,CAAC,SAAiB;IACrD,OAAO,SAAS,KAAK,wBAAwB,IAAI,SAAS,KAAK,GAAG,wBAAwB,KAAK,CAAC;AAClG,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAe;IAClD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IACzC,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IAC7D,MAAM,MAAM,GAAG,MAId,CAAC;IACF,IAAI,MAAM,CAAC,EAAE,KAAK,KAAK;QAAE,OAAO,EAAE,CAAC;IACnC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC,MAA6B,CAAC;IAC9E,IAAI,MAAM,CAAC,KAAK,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACrD,MAAM,KAAK,GAAG,MAAM,CAAC,KAA6B,CAAC;QACnD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAC,MAA6B,CAAC;QAC5E,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,OAAO,MAAM,CAAC,KAA4B,CAAC;IAC9E,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,wBAAwB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAClF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAuB;IACzD,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,KAAK,EAAE,gBAAgB,EAAE;KAC1B,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,133 @@
1
+ {
2
+ "name": "@drscrewdriver/dsh-better-display",
3
+ "version": "0.3.3-fork.1",
4
+ "description": "A calmer reading view for DeepSeek Harness: native process details, live reasoning, and clean final answers. Fork adds answer message bubbles with a settings switch.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "main": "lib/dsh-better-display.js",
8
+ "types": "lib/types/dsh-better-display.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./lib/types/dsh-better-display.d.ts",
12
+ "default": "./lib/dsh-better-display.js"
13
+ },
14
+ "./client": {
15
+ "types": "./lib/types/client/index.d.ts",
16
+ "default": "./lib/client.js"
17
+ },
18
+ "./package.json": "./package.json"
19
+ },
20
+ "dsh": {
21
+ "bundle": {
22
+ "patch": "./cordis.patch.yml"
23
+ },
24
+ "client": {
25
+ "platform": "web",
26
+ "inject": [
27
+ "@deepseek-ai/dsh-api-session-controller",
28
+ "@deepseek-ai/dsh-client-ui-chat",
29
+ "@deepseek-ai/dsh-client-ui-conversation",
30
+ "@deepseek-ai/dsh-client-ui-renderer",
31
+ "@deepseek-ai/dsh-client-ui-session"
32
+ ]
33
+ }
34
+ },
35
+ "scripts": {
36
+ "build": "node scripts/check-harness-compat.mjs && tsc -p tsconfig.json && tsdown",
37
+ "check:harness": "node scripts/check-harness-compat.mjs",
38
+ "test:official": "node scripts/verify-official-bridge.mjs",
39
+ "test:auto-fold": "node scripts/verify-auto-fold.mjs",
40
+ "typecheck": "tsc -p tsconfig.json --noEmit",
41
+ "test": "node --import tsx/esm --test tests/*.test.ts",
42
+ "link:harness": "node scripts/link-harness-dependencies.mjs"
43
+ },
44
+ "peerDependencies": {
45
+ "@deepseek-ai/cordis": "~4.0.4",
46
+ "@deepseek-ai/dsh-api-session-controller": ">=0.1.7-rc.1 <0.1.8",
47
+ "@deepseek-ai/dsh-attachment": ">=0.1.7-rc.1 <0.1.8",
48
+ "@deepseek-ai/dsh-client-store": ">=0.1.7-rc.1 <0.1.8",
49
+ "@deepseek-ai/dsh-client-ui-chat": ">=0.1.7-rc.1 <0.1.8",
50
+ "@deepseek-ai/dsh-client-ui-conversation": ">=0.1.7-rc.1 <0.1.8",
51
+ "@deepseek-ai/dsh-client-ui-primitives": ">=0.1.7-rc.1 <0.1.8",
52
+ "@deepseek-ai/dsh-client-ui-renderer": ">=0.1.7-rc.1 <0.1.8",
53
+ "@deepseek-ai/dsh-client-ui-session": ">=0.1.7-rc.1 <0.1.8",
54
+ "@deepseek-ai/dsh-client-ui-slots": ">=0.1.7-rc.1 <0.1.8",
55
+ "@deepseek-ai/dsh-client-ui-tool": ">=0.1.7-rc.1 <0.1.8",
56
+ "@deepseek-ai/dsh-session": ">=0.1.7-rc.1 <0.1.8",
57
+ "@deepseek-ai/dsh-util-workspace-path": ">=0.1.7-rc.1 <0.1.8",
58
+ "react": "^18.2.0"
59
+ },
60
+ "devDependencies": {
61
+ "@deepseek-ai/dsh-api-remotes": "0.1.7-rc.2",
62
+ "@deepseek-ai/dsh-api-session-controller": "0.1.7-rc.2",
63
+ "@deepseek-ai/dsh-client-connection": "0.1.7-rc.2",
64
+ "@deepseek-ai/dsh-session-turn-outline": "0.1.7-rc.2",
65
+ "@types/mdast": "^4.0.4",
66
+ "@types/node": "^22.20.0",
67
+ "@types/react": "~18.3.1",
68
+ "lightningcss": "^1.33.0",
69
+ "tsdown": "^0.22.2",
70
+ "tsx": "^4.22.4",
71
+ "typescript": "^6.0.3"
72
+ },
73
+ "dependencies": {
74
+ "clsx": "^2.0.0",
75
+ "katex": "^0.16.47",
76
+ "mdast-util-from-markdown": "^2.0.3",
77
+ "mdast-util-gfm": "^3.1.0",
78
+ "mdast-util-math": "^3.0.0",
79
+ "micromark-core-commonmark": "^2.0.3",
80
+ "micromark-extension-gfm": "^3.0.0",
81
+ "micromark-extension-math": "^3.1.0",
82
+ "micromark-factory-space": "^2.0.1",
83
+ "micromark-util-character": "^2.1.1",
84
+ "micromark-util-classify-character": "^2.0.1",
85
+ "micromark-util-sanitize-uri": "^2.0.1",
86
+ "micromark-util-symbol": "^2.0.1",
87
+ "micromark-util-types": "^2.0.2"
88
+ },
89
+ "files": [
90
+ "lib",
91
+ "skills",
92
+ "src",
93
+ "tests",
94
+ "scripts",
95
+ "cordis.yml",
96
+ "cordis.patch.yml",
97
+ "dshx.yml",
98
+ "tsconfig.json",
99
+ "tsdown.config.ts",
100
+ "README.md",
101
+ "README.en.md",
102
+ "DESIGN.md",
103
+ "LICENSE",
104
+ "THIRD_PARTY_NOTICES.md",
105
+ "CHANGELOG.md",
106
+ "compat",
107
+ "docs"
108
+ ],
109
+ "engines": {
110
+ "node": "^22.19.0 || >=24.0.0"
111
+ },
112
+ "repository": {
113
+ "type": "git",
114
+ "url": "git+https://github.com/drscrewdriver/dsh-better-display.git"
115
+ },
116
+ "homepage": "https://github.com/drscrewdriver/dsh-better-display#readme",
117
+ "bugs": {
118
+ "url": "https://github.com/drscrewdriver/dsh-better-display/issues"
119
+ },
120
+ "publishConfig": {
121
+ "access": "public"
122
+ },
123
+ "keywords": [
124
+ "deepseek-harness",
125
+ "dsh",
126
+ "dsh-plugin",
127
+ "dshx",
128
+ "conversation",
129
+ "reasoning",
130
+ "streaming",
131
+ "accessibility"
132
+ ]
133
+ }
@@ -0,0 +1,26 @@
1
+ import { createRequire } from 'node:module';
2
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
3
+ import { resolve } from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ const require = createRequire(import.meta.url);
6
+ const deps = createRequire(require.resolve('tsdown'));
7
+ const { rolldown } = await import(pathToFileURL(deps.resolve('rolldown')).href);
8
+ const { transform } = deps('lightningcss');
9
+ const build = await rolldown({ input: process.argv[2] ?? 'tests/browser-motion.tsx', platform: 'browser', transform: { jsx: { runtime: 'automatic' }, define: { 'process.env.NODE_ENV': JSON.stringify('production') } }, plugins: [{
10
+ name: 'fixture-css',
11
+ resolveId(source, importer) { if (source.endsWith('.module.css')) return resolve(importer ? resolve(importer,'..') : '.',source) + '.mjs'; },
12
+ async load(id) {
13
+ if (!id.endsWith('.module.css.mjs')) return;
14
+ const path = id.slice(0, -4);
15
+ const {code,exports} = transform({filename:path,code:await readFile(path),cssModules:{pattern:'[hash]_[local]'}});
16
+ const map=Object.fromEntries(Object.entries(exports).map(([key,value])=>[key,value.name]));
17
+ return `const style=document.createElement('style');style.textContent=${JSON.stringify(code.toString())};document.head.append(style);export default ${JSON.stringify(map)};`;
18
+ },
19
+ }] });
20
+ await mkdir('.delivery',{recursive:true});
21
+ const result = await build.generate({ format:'iife', name:'ReaderMotionFixture' });
22
+ const js=result.output.find(x=>x.type==='chunk').code;
23
+ await writeFile('.delivery/motion-fixture.js',js);
24
+ await writeFile('.delivery/motion-fixture.html',`<!doctype html><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Reader transition verification</title><style>body{margin:0;font:16px/1.75 system-ui;background:#fff;color:#242424;--dsw-alias-label-primary:#242424;--dsw-alias-label-secondary:#666;--dsw-alias-label-tertiary:#888;--dsw-alias-bg-base:#fff;--dsw-alias-bg-module-platform:#f6f7f8;--dsw-alias-border-l2:#dedede}button{cursor:pointer}</style><div id="app"></div><script>${js.replaceAll('</script','<\\/script')}</script>`);
25
+ await build.close();
26
+ console.log('Built .delivery/motion-fixture.html using actual plugin components');
@@ -0,0 +1,71 @@
1
+ /** Upgrade gate for the public composition adapter and remaining Markdown fork. */
2
+ import { readFileSync, writeFileSync } from 'node:fs';
3
+ import { createHash } from 'node:crypto';
4
+ import { execFileSync } from 'node:child_process';
5
+ import { homedir } from 'node:os';
6
+ import { join, resolve } from 'node:path';
7
+ import { createRequire } from 'node:module';
8
+
9
+ const root = resolve(import.meta.dirname, '..');
10
+ const harness = resolve(process.env.DSHX_HARNESS?.trim() || readFileSync(join(homedir(), '.config/dshx/harness'), 'utf8').trim());
11
+ const baselineFile = join(root, 'compat/harness-rc2.json');
12
+ const ts = createRequire(join(root, 'package.json'))('typescript');
13
+ const files = [
14
+ 'packages/client/ui-slots/src/index.ts',
15
+ 'packages/client/ui-slots/src/renderer.ts',
16
+ 'packages/client/ui-renderer/src/client/registry.ts',
17
+ 'packages/client/ui-renderer/src/client/scoped-slots.tsx',
18
+ 'packages/client/ui-chat/src/client/contract/slots.ts',
19
+ 'packages/client/ui-tool/src/client/contract/slots.ts',
20
+ 'packages/client/ui-deliverables/src/client/Deliverables.tsx',
21
+ 'packages/client/ui-chat/src/client/chat/AssistantMarkdown.tsx',
22
+ 'packages/client/ui-chat/src/client/chat/MessageItem.tsx',
23
+ 'packages/client/ui-chat/src/client/chat/AssistantNodeView.tsx',
24
+ 'packages/client/ui-chat/src/client/chat/TurnTailNodeView.tsx',
25
+ 'packages/client/ui-chat/src/client/chat/TurnProcessNodeView.tsx',
26
+ 'packages/client/ui-tool/src/client/tool/models/tool-call-model.ts',
27
+ ...['MarkdownText.tsx', 'render.tsx', 'parse.ts', 'incremental.ts', 'katex.tsx'].map(name => `packages/client/ui-primitives/src/markdown/${name}`),
28
+ ];
29
+ const hashes = Object.fromEntries(files.map(file => [file, createHash('sha256').update(readFileSync(join(harness, file))).digest('hex')]));
30
+ const registrations = [];
31
+ for (const path of execFileSync('rg', ['--files', 'packages/client', '-g', '*.ts', '-g', '*.tsx'], { cwd: harness, encoding: 'utf8' }).trim().split('\n')) {
32
+ if (!path.includes('/src/client/')) continue;
33
+ const text = readFileSync(join(harness, path), 'utf8');
34
+ if (!/conversation\.chat\.|tool\.call\.|conversation\.message\./u.test(text)) continue;
35
+ const file = ts.createSourceFile(path, text, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
36
+ function visit(node) {
37
+ if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && node.expression.name.text === 'register') {
38
+ const options = node.arguments[0];
39
+ if (options && ts.isObjectLiteralExpression(options)) {
40
+ const fields = {};
41
+ for (const p of options.properties) {
42
+ if (ts.isPropertyAssignment(p) && ts.isStringLiteral(p.initializer)) fields[p.name.getText(file).replaceAll("'", '').replaceAll('"', '')] = p.initializer.text;
43
+ }
44
+ if (/^(conversation\.chat\.|tool\.call\.|conversation\.message\.)/u.test(fields.name ?? '')) {
45
+ registrations.push(`${fields.name} | ${fields.key ?? fields.id ?? '(chain/single)'} | ${path}`);
46
+ }
47
+ }
48
+ }
49
+ ts.forEachChild(node, visit);
50
+ }
51
+ visit(file);
52
+ }
53
+ registrations.sort();
54
+ const current = {
55
+ harnessVersion: JSON.parse(readFileSync(join(harness, 'packages/client/ui-chat/package.json'), 'utf8')).version,
56
+ hashes, registrations,
57
+ };
58
+ if (process.argv.includes('--record')) {
59
+ writeFileSync(baselineFile, JSON.stringify(current, null, 2) + '\n');
60
+ console.log(`Recorded candidate baseline: ${current.harnessVersion}; run build, fixtures and DSH acceptance before committing it.`);
61
+ } else {
62
+ const baseline = JSON.parse(readFileSync(baselineFile, 'utf8'));
63
+ const changed = files.filter(file => current.hashes[file] !== baseline.hashes[file]);
64
+ const added = registrations.filter(row => !baseline.registrations.includes(row));
65
+ const removed = baseline.registrations.filter(row => !registrations.includes(row));
66
+ if (current.harnessVersion !== baseline.harnessVersion || changed.length || added.length || removed.length) {
67
+ console.error(JSON.stringify({ compatible: 'review-required', target: current.harnessVersion, changedContractsOrForkSources: changed, addedRegistrations: added, removedRegistrations: removed }, null, 2));
68
+ console.error('Review the differences and run the official bridge/visual tests. --record alone is not compatibility proof.');
69
+ process.exitCode = 1;
70
+ } else console.log(`Harness compatibility baseline passed (${current.harnessVersion}; ${registrations.length} official registrations).`);
71
+ }
@@ -0,0 +1,54 @@
1
+ import { existsSync, mkdirSync, symlinkSync, realpathSync, readFileSync } from 'node:fs';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ import { createRequire } from 'node:module';
4
+
5
+ const root = resolve(process.argv[2] || '');
6
+ if (!process.argv[2] || !existsSync(join(root, 'tools/dshx/src/client-build.js'))) throw new Error('Pass a prepared Harness checkout.');
7
+ const local = resolve('node_modules');
8
+ mkdirSync(local, { recursive: true });
9
+ const shared = {
10
+ '@deepseek-ai/cordis': 'vendor/cordis',
11
+ '@deepseek-ai/dsh-api-remotes': 'packages/api/remotes',
12
+ '@deepseek-ai/dsh-api-session-controller': 'packages/api/session-controller',
13
+ '@deepseek-ai/dsh-client-connection': 'packages/client/connection',
14
+ '@deepseek-ai/dsh-session-turn-outline': 'packages/session/session-turn-outline',
15
+ '@deepseek-ai/dsh-client-store': 'packages/client/store',
16
+ '@deepseek-ai/dsh-client-ui-chat': 'packages/client/ui-chat',
17
+ '@deepseek-ai/dsh-client-ui-conversation': 'packages/client/ui-conversation',
18
+ '@deepseek-ai/dsh-client-ui-primitives': 'packages/client/ui-primitives',
19
+ '@deepseek-ai/dsh-client-ui-renderer': 'packages/client/ui-renderer',
20
+ '@deepseek-ai/dsh-client-ui-session': 'packages/client/ui-session',
21
+ '@deepseek-ai/dsh-client-ui-slots': 'packages/client/ui-slots',
22
+ '@deepseek-ai/dsh-client-ui-tool': 'packages/client/ui-tool',
23
+ '@deepseek-ai/dsh-attachment': 'packages/attachment/attachment',
24
+ '@deepseek-ai/dsh-session': 'packages/core/session',
25
+ '@deepseek-ai/dsh-util-workspace-path': 'packages/util/workspace-path',
26
+ };
27
+ function link(name, target) {
28
+ if (!existsSync(target)) throw new Error(`Missing Harness dependency target: ${name} (${target})`);
29
+ const destination = join(local, name);
30
+ mkdirSync(dirname(destination), { recursive: true });
31
+ if (existsSync(destination)) {
32
+ if (realpathSync(destination) !== realpathSync(target)) throw new Error(`Dependency mismatch: ${name}`);
33
+ return;
34
+ }
35
+ symlinkSync(target, destination);
36
+ }
37
+ for (const [name, path] of Object.entries(shared)) link(name, join(root, path));
38
+ const require = createRequire(join(root, 'packages/client/ui-conversation/package.json'));
39
+ const rootRequire = createRequire(join(root, 'package.json'));
40
+ for (const name of ['react', '@types/react']) link(name, dirname(require.resolve(`${name}/package.json`)));
41
+ for (const name of ['@types/node', 'typescript', 'tsdown', 'tsx']) link(name, dirname(rootRequire.resolve(`${name}/package.json`)));
42
+ for (const name of ['@types/mdast', 'clsx', 'katex', 'mdast-util-from-markdown', 'mdast-util-gfm', 'mdast-util-math', 'micromark-core-commonmark', 'micromark-extension-gfm', 'micromark-extension-math', 'micromark-factory-space', 'micromark-util-character', 'micromark-util-classify-character', 'micromark-util-sanitize-uri', 'micromark-util-symbol', 'micromark-util-types']) {
43
+ link(name, join(root, 'packages/client/ui-primitives/node_modules', name));
44
+ }
45
+ mkdirSync(join(local, '.bin'), { recursive: true });
46
+ for (const name of ['typescript', 'tsdown']) {
47
+ const pkg = JSON.parse(readFileSync(join(local, name, 'package.json'), 'utf8'));
48
+ const bins = typeof pkg.bin === 'string' ? { [name]: pkg.bin } : pkg.bin;
49
+ for (const [command, path] of Object.entries(bins)) {
50
+ const target = join(local, '.bin', command);
51
+ if (!existsSync(target)) symlinkSync(join(local, name, path), target);
52
+ }
53
+ }
54
+ console.log('Development dependencies linked to the selected Harness; no package download or Harness mutation.');
@@ -0,0 +1,114 @@
1
+ /** Real Reader interaction regression, isolated from the user's Host and data. */
2
+ import assert from 'node:assert/strict';
3
+ import { createRequire } from 'node:module';
4
+ import { readFile, mkdir, writeFile } from 'node:fs/promises';
5
+ import { createServer } from 'node:http';
6
+ import { homedir } from 'node:os';
7
+ import { dirname, join, resolve } from 'node:path';
8
+ import { pathToFileURL } from 'node:url';
9
+
10
+ const root = resolve(import.meta.dirname, '..');
11
+ const harness = process.env.DSHX_HARNESS;
12
+ if (!harness) throw new Error('Set DSHX_HARNESS to the target checkout.');
13
+ const require = createRequire(join(root, 'package.json'));
14
+ const webRequire = createRequire(join(harness, 'packages/client/web/package.json'));
15
+ const { build } = await import(pathToFileURL(createRequire(require.resolve('tsx')).resolve('esbuild')).href);
16
+ const { launchPinnedChromium } = await import(pathToFileURL(join(homedir(), '.codex/playwright-runtime/runtime.mjs')).href);
17
+ const out = join(root, '.evidence/auto-fold');
18
+ await mkdir(out, { recursive: true });
19
+ await build({
20
+ entryPoints: [join(root, 'tests/browser-auto-fold.tsx')], outfile: join(out, 'fixture.js'),
21
+ bundle: true, platform: 'browser', format: 'esm', jsx: 'automatic',
22
+ alias: {
23
+ '@deepseek-ai/dsh-client-ui-primitives': join(harness, 'packages/client/ui-primitives/src/index.ts'),
24
+ react: dirname(require.resolve('react/package.json')), 'react-dom': dirname(webRequire.resolve('react-dom/package.json')),
25
+ },
26
+ loader: { '.woff2': 'dataurl', '.woff': 'dataurl', '.ttf': 'dataurl', '.svg': 'dataurl' },
27
+ });
28
+ const server = createServer(async (req, res) => {
29
+ const file = req.url === '/fixture.js' ? 'fixture.js' : req.url === '/fixture.css' ? 'fixture.css' : null;
30
+ if (file) { res.setHeader('Content-Type', file.endsWith('.js') ? 'text/javascript' : 'text/css'); res.end(await readFile(join(out, file))); return; }
31
+ if (req.url !== '/') { res.writeHead(404); res.end(); return; }
32
+ res.setHeader('Content-Type', 'text/html');
33
+ res.end('<!doctype html><html lang="zh"><meta charset="utf-8"><link rel="stylesheet" href="/fixture.css"><style>body{margin:0;font:14px/1.6 system-ui;--dsw-alias-label-primary:#222;--dsw-alias-label-secondary:#666;--dsw-alias-label-tertiary:#888;--dsw-alias-bg-base:#fff;--dsw-alias-border-l2:#ddd}button{cursor:pointer}</style><div id="app"></div><script type="module" src="/fixture.js"></script></html>');
34
+ });
35
+ await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
36
+ let browser;
37
+ const results = [];
38
+ try {
39
+ browser = await launchPinnedChromium();
40
+ for (const reducedMotion of ['no-preference', 'reduce']) {
41
+ const page = await browser.newPage({ viewport: { width: 1200, height: 1000 }, reducedMotion });
42
+ page.setDefaultTimeout(4000);
43
+ const errors = [];
44
+ page.on('pageerror', error => errors.push(String(error)));
45
+ await page.goto(`http://127.0.0.1:${server.address().port}/`);
46
+ const closed = page.locator('[data-reader-turn="1"]');
47
+ const live = page.locator('[data-reader-turn="2"]');
48
+ const completedThought = closed.getByText('已完成思考 0', { exact: true });
49
+ const oldLiveThought = live.getByText('进行中思考 0', { exact: true });
50
+ const latestThought = live.getByText('进行中思考 1', { exact: true });
51
+ const toggle = () => page.getByRole('button', { name: /^自动折叠[开关]$/ }).click();
52
+ await page.getByRole('button', { name: '自动折叠开', exact: true }).waitFor();
53
+ await latestThought.waitFor();
54
+ assert.equal(await completedThought.count(), 0);
55
+
56
+ // Reading while auto-fold is off used to persist a manual expansion forever.
57
+ await toggle();
58
+ await completedThought.click();
59
+ assert.ok(Object.values(await page.evaluate(() => window.autoFoldFixture.state().expanded)).includes(true));
60
+ await toggle();
61
+ await completedThought.waitFor({ state: 'hidden' });
62
+ await latestThought.waitFor();
63
+ await closed.getByText('最终回答始终保留', { exact: true }).waitFor();
64
+
65
+ // A prior-steps disclosure has its own state, separate from the store.
66
+ await live.getByRole('button', { name: '展开此前步骤', exact: true }).click();
67
+ await oldLiveThought.waitFor();
68
+ await toggle();
69
+ await toggle();
70
+ await oldLiveThought.waitFor({ state: 'hidden' });
71
+ await latestThought.waitFor();
72
+
73
+ // Fresh manual choices still work after automatic folding is restored.
74
+ await closed.getByRole('button', { name: '展开思考与过程', exact: true }).click();
75
+ await completedThought.waitFor();
76
+ await page.evaluate(() => window.autoFoldFixture.preference(false));
77
+ await page.getByRole('button', { name: '自动折叠关', exact: true }).waitFor();
78
+ await page.evaluate(() => window.autoFoldFixture.preference(true));
79
+ await completedThought.waitFor({ state: 'hidden' });
80
+
81
+ // Active text selection still protects reading until the user clears it.
82
+ await toggle();
83
+ await completedThought.evaluate(async element => {
84
+ const range = document.createRange();
85
+ range.selectNodeContents(element);
86
+ document.getSelection().removeAllRanges();
87
+ document.getSelection().addRange(range);
88
+ document.dispatchEvent(new Event('selectionchange'));
89
+ await new Promise(requestAnimationFrame);
90
+ });
91
+ await page.evaluate(() => window.autoFoldFixture.preference(true));
92
+ await page.getByRole('button', { name: '自动折叠开', exact: true }).waitFor();
93
+ await closed.getByRole('button', { name: '收起思考与过程', exact: true }).waitFor();
94
+ assert.equal(await page.evaluate(() => document.getSelection().toString()), '已完成思考 0');
95
+ await page.evaluate(() => document.getSelection().removeAllRanges());
96
+ await completedThought.waitFor({ state: 'hidden' });
97
+
98
+ // Rapid reversal must settle with automatic folding enabled.
99
+ for (let i = 0; i < 6; i++) await toggle();
100
+ await completedThought.waitFor({ state: 'hidden' });
101
+ await oldLiveThought.waitFor({ state: 'hidden' });
102
+ await latestThought.waitFor();
103
+ assert.deepEqual(errors, []);
104
+ assert.equal(await page.getByText('此内容暂时无法展示', { exact: false }).count(), 0);
105
+ await page.screenshot({ path: join(out, `${reducedMotion}.png`) });
106
+ results.push({ reducedMotion, passed: true, paths: ['read-while-off', 'prior-steps-override', 'new-manual-choice', 'settings-toggle', 'active-selection', 'rapid-reversal', 'latest-and-final-content'] });
107
+ await page.close();
108
+ }
109
+ await writeFile(join(out, 'result.json'), JSON.stringify({ passed: true, results }, null, 2));
110
+ console.log(JSON.stringify({ passed: true, results }));
111
+ } finally {
112
+ await browser?.close();
113
+ await new Promise(resolve => server.close(resolve));
114
+ }