@flanksource/clicky-ui 0.3.46 → 0.3.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (379) hide show
  1. package/NOTICE.md +11 -0
  2. package/dist/ai.cjs +13 -8
  3. package/dist/ai.cjs.map +1 -1
  4. package/dist/ai.js +7 -2
  5. package/dist/ai.js.map +1 -1
  6. package/dist/components/ErrorWrapper.cjs +2 -3
  7. package/dist/components/ErrorWrapper.cjs.map +1 -1
  8. package/dist/components/ErrorWrapper.d.ts.map +1 -1
  9. package/dist/components/ErrorWrapper.js +3 -4
  10. package/dist/components/ErrorWrapper.js.map +1 -1
  11. package/dist/data/Clicky.cjs +3 -0
  12. package/dist/data/Clicky.cjs.map +1 -1
  13. package/dist/data/Clicky.js +3 -0
  14. package/dist/data/Clicky.js.map +1 -1
  15. package/dist/data/FilterPill.cjs +15 -2
  16. package/dist/data/FilterPill.cjs.map +1 -1
  17. package/dist/data/FilterPill.d.ts +1 -1
  18. package/dist/data/FilterPill.d.ts.map +1 -1
  19. package/dist/data/FilterPill.js +15 -2
  20. package/dist/data/FilterPill.js.map +1 -1
  21. package/dist/data/LogViewer.cjs +27 -8
  22. package/dist/data/LogViewer.cjs.map +1 -1
  23. package/dist/data/LogViewer.d.ts +11 -3
  24. package/dist/data/LogViewer.d.ts.map +1 -1
  25. package/dist/data/LogViewer.js +27 -8
  26. package/dist/data/LogViewer.js.map +1 -1
  27. package/dist/data/Properties.cjs +2 -15
  28. package/dist/data/Properties.cjs.map +1 -1
  29. package/dist/data/Properties.d.ts +4 -0
  30. package/dist/data/Properties.d.ts.map +1 -1
  31. package/dist/data/Properties.js +2 -15
  32. package/dist/data/Properties.js.map +1 -1
  33. package/dist/data/PropertyValue.cjs +37 -0
  34. package/dist/data/PropertyValue.cjs.map +1 -0
  35. package/dist/data/PropertyValue.d.ts +6 -0
  36. package/dist/data/PropertyValue.d.ts.map +1 -0
  37. package/dist/data/PropertyValue.js +37 -0
  38. package/dist/data/PropertyValue.js.map +1 -0
  39. package/dist/data/Tree.cjs +4 -3
  40. package/dist/data/Tree.cjs.map +1 -1
  41. package/dist/data/Tree.d.ts +3 -1
  42. package/dist/data/Tree.d.ts.map +1 -1
  43. package/dist/data/Tree.js +4 -3
  44. package/dist/data/Tree.js.map +1 -1
  45. package/dist/data/ai/ChatFab.cjs +1 -1
  46. package/dist/data/ai/ChatFab.cjs.map +1 -1
  47. package/dist/data/ai/ChatFab.js +1 -1
  48. package/dist/data/ai/ChatFab.js.map +1 -1
  49. package/dist/data/ai/ChatWindow.cjs +106 -171
  50. package/dist/data/ai/ChatWindow.cjs.map +1 -1
  51. package/dist/data/ai/ChatWindow.d.ts +6 -2
  52. package/dist/data/ai/ChatWindow.d.ts.map +1 -1
  53. package/dist/data/ai/ChatWindow.header.cjs +104 -0
  54. package/dist/data/ai/ChatWindow.header.cjs.map +1 -0
  55. package/dist/data/ai/ChatWindow.header.d.ts +29 -0
  56. package/dist/data/ai/ChatWindow.header.d.ts.map +1 -0
  57. package/dist/data/ai/ChatWindow.header.js +104 -0
  58. package/dist/data/ai/ChatWindow.header.js.map +1 -0
  59. package/dist/data/ai/ChatWindow.js +107 -172
  60. package/dist/data/ai/ChatWindow.js.map +1 -1
  61. package/dist/data/ai/ChatWindow.placement.cjs +95 -0
  62. package/dist/data/ai/ChatWindow.placement.cjs.map +1 -0
  63. package/dist/data/ai/ChatWindow.placement.d.ts +32 -0
  64. package/dist/data/ai/ChatWindow.placement.d.ts.map +1 -0
  65. package/dist/data/ai/ChatWindow.placement.js +95 -0
  66. package/dist/data/ai/ChatWindow.placement.js.map +1 -0
  67. package/dist/data/ai/SessionChatComposer.cjs +3 -1
  68. package/dist/data/ai/SessionChatComposer.cjs.map +1 -1
  69. package/dist/data/ai/SessionChatComposer.d.ts +4 -1
  70. package/dist/data/ai/SessionChatComposer.d.ts.map +1 -1
  71. package/dist/data/ai/SessionChatComposer.js +3 -1
  72. package/dist/data/ai/SessionChatComposer.js.map +1 -1
  73. package/dist/data/ai/SessionInspector.cjs +68 -72
  74. package/dist/data/ai/SessionInspector.cjs.map +1 -1
  75. package/dist/data/ai/SessionInspector.composer-slot.cjs +8 -0
  76. package/dist/data/ai/SessionInspector.composer-slot.cjs.map +1 -0
  77. package/dist/data/ai/SessionInspector.composer-slot.d.ts +9 -0
  78. package/dist/data/ai/SessionInspector.composer-slot.d.ts.map +1 -0
  79. package/dist/data/ai/SessionInspector.composer-slot.js +8 -0
  80. package/dist/data/ai/SessionInspector.composer-slot.js.map +1 -0
  81. package/dist/data/ai/SessionInspector.d.ts +6 -1
  82. package/dist/data/ai/SessionInspector.d.ts.map +1 -1
  83. package/dist/data/ai/SessionInspector.js +69 -73
  84. package/dist/data/ai/SessionInspector.js.map +1 -1
  85. package/dist/data/ai/SessionInspector.legacy.cjs +41 -42
  86. package/dist/data/ai/SessionInspector.legacy.cjs.map +1 -1
  87. package/dist/data/ai/SessionInspector.legacy.d.ts.map +1 -1
  88. package/dist/data/ai/SessionInspector.legacy.js +41 -42
  89. package/dist/data/ai/SessionInspector.legacy.js.map +1 -1
  90. package/dist/data/ai/SessionInspector.remote-view.cjs +14 -9
  91. package/dist/data/ai/SessionInspector.remote-view.cjs.map +1 -1
  92. package/dist/data/ai/SessionInspector.remote-view.d.ts +6 -2
  93. package/dist/data/ai/SessionInspector.remote-view.d.ts.map +1 -1
  94. package/dist/data/ai/SessionInspector.remote-view.js +14 -9
  95. package/dist/data/ai/SessionInspector.remote-view.js.map +1 -1
  96. package/dist/data/ai/SessionInspector.remote.cjs +84 -16
  97. package/dist/data/ai/SessionInspector.remote.cjs.map +1 -1
  98. package/dist/data/ai/SessionInspector.remote.d.ts +42 -7
  99. package/dist/data/ai/SessionInspector.remote.d.ts.map +1 -1
  100. package/dist/data/ai/SessionInspector.remote.js +86 -18
  101. package/dist/data/ai/SessionInspector.remote.js.map +1 -1
  102. package/dist/data/ai/SessionInspector.transcript.cjs +5 -0
  103. package/dist/data/ai/SessionInspector.transcript.cjs.map +1 -1
  104. package/dist/data/ai/SessionInspector.transcript.d.ts.map +1 -1
  105. package/dist/data/ai/SessionInspector.transcript.js +5 -0
  106. package/dist/data/ai/SessionInspector.transcript.js.map +1 -1
  107. package/dist/data/ai/SessionTail.cjs +63 -0
  108. package/dist/data/ai/SessionTail.cjs.map +1 -0
  109. package/dist/data/ai/SessionTail.d.ts +14 -0
  110. package/dist/data/ai/SessionTail.d.ts.map +1 -0
  111. package/dist/data/ai/SessionTail.js +63 -0
  112. package/dist/data/ai/SessionTail.js.map +1 -0
  113. package/dist/data/ai/SessionViewer.cjs +10 -3
  114. package/dist/data/ai/SessionViewer.cjs.map +1 -1
  115. package/dist/data/ai/SessionViewer.d.ts +7 -1
  116. package/dist/data/ai/SessionViewer.d.ts.map +1 -1
  117. package/dist/data/ai/SessionViewer.js +10 -3
  118. package/dist/data/ai/SessionViewer.js.map +1 -1
  119. package/dist/data/ai/SessionViewer.unified.d.ts +14 -0
  120. package/dist/data/ai/SessionViewer.unified.d.ts.map +1 -1
  121. package/dist/data/ai/index.d.ts +4 -3
  122. package/dist/data/ai/index.d.ts.map +1 -1
  123. package/dist/data/ai/use-session-scroll.cjs +30 -6
  124. package/dist/data/ai/use-session-scroll.cjs.map +1 -1
  125. package/dist/data/ai/use-session-scroll.d.ts +7 -0
  126. package/dist/data/ai/use-session-scroll.d.ts.map +1 -1
  127. package/dist/data/ai/use-session-scroll.js +30 -6
  128. package/dist/data/ai/use-session-scroll.js.map +1 -1
  129. package/dist/data/chat/Chat.cjs +1 -1
  130. package/dist/data/chat/Chat.cjs.map +1 -1
  131. package/dist/data/chat/Chat.js +1 -1
  132. package/dist/data/chat/Chat.js.map +1 -1
  133. package/dist/data/chat/ChatRuntimeToolbar.cjs +4 -4
  134. package/dist/data/chat/ChatRuntimeToolbar.cjs.map +1 -1
  135. package/dist/data/chat/ChatRuntimeToolbar.d.ts.map +1 -1
  136. package/dist/data/chat/ChatRuntimeToolbar.js +4 -4
  137. package/dist/data/chat/ChatRuntimeToolbar.js.map +1 -1
  138. package/dist/data/chat/PromptInput.cjs +4 -2
  139. package/dist/data/chat/PromptInput.cjs.map +1 -1
  140. package/dist/data/chat/PromptInput.d.ts +5 -1
  141. package/dist/data/chat/PromptInput.d.ts.map +1 -1
  142. package/dist/data/chat/PromptInput.js +4 -2
  143. package/dist/data/chat/PromptInput.js.map +1 -1
  144. package/dist/data/diagnostics/ErrorDetails.cjs +13 -2
  145. package/dist/data/diagnostics/ErrorDetails.cjs.map +1 -1
  146. package/dist/data/diagnostics/ErrorDetails.d.ts +3 -1
  147. package/dist/data/diagnostics/ErrorDetails.d.ts.map +1 -1
  148. package/dist/data/diagnostics/ErrorDetails.js +14 -3
  149. package/dist/data/diagnostics/ErrorDetails.js.map +1 -1
  150. package/dist/data/diagnostics/FrameSourceWindow.cjs +3 -2
  151. package/dist/data/diagnostics/FrameSourceWindow.cjs.map +1 -1
  152. package/dist/data/diagnostics/FrameSourceWindow.d.ts.map +1 -1
  153. package/dist/data/diagnostics/FrameSourceWindow.js +3 -2
  154. package/dist/data/diagnostics/FrameSourceWindow.js.map +1 -1
  155. package/dist/data/diagnostics/error-diagnostics.cjs +5 -0
  156. package/dist/data/diagnostics/error-diagnostics.cjs.map +1 -1
  157. package/dist/data/diagnostics/error-diagnostics.d.ts +1 -0
  158. package/dist/data/diagnostics/error-diagnostics.d.ts.map +1 -1
  159. package/dist/data/diagnostics/error-diagnostics.js +6 -1
  160. package/dist/data/diagnostics/error-diagnostics.js.map +1 -1
  161. package/dist/data/har/HarPanel.cjs +3 -1
  162. package/dist/data/har/HarPanel.cjs.map +1 -1
  163. package/dist/data/har/HarPanel.d.ts +4 -1
  164. package/dist/data/har/HarPanel.d.ts.map +1 -1
  165. package/dist/data/har/HarPanel.js +3 -1
  166. package/dist/data/har/HarPanel.js.map +1 -1
  167. package/dist/data/test-runner/Expectation.cjs +57 -0
  168. package/dist/data/test-runner/Expectation.cjs.map +1 -0
  169. package/dist/data/test-runner/Expectation.d.ts +19 -0
  170. package/dist/data/test-runner/Expectation.d.ts.map +1 -0
  171. package/dist/data/test-runner/Expectation.js +57 -0
  172. package/dist/data/test-runner/Expectation.js.map +1 -0
  173. package/dist/data/test-runner/MarkIcons.cjs +38 -0
  174. package/dist/data/test-runner/MarkIcons.cjs.map +1 -0
  175. package/dist/data/test-runner/MarkIcons.d.ts +15 -0
  176. package/dist/data/test-runner/MarkIcons.d.ts.map +1 -0
  177. package/dist/data/test-runner/MarkIcons.js +38 -0
  178. package/dist/data/test-runner/MarkIcons.js.map +1 -0
  179. package/dist/data/test-runner/TestDetailPanel.cjs +74 -42
  180. package/dist/data/test-runner/TestDetailPanel.cjs.map +1 -1
  181. package/dist/data/test-runner/TestDetailPanel.d.ts.map +1 -1
  182. package/dist/data/test-runner/TestDetailPanel.js +76 -44
  183. package/dist/data/test-runner/TestDetailPanel.js.map +1 -1
  184. package/dist/data/test-runner/TestFailureDetail.cjs +23 -27
  185. package/dist/data/test-runner/TestFailureDetail.cjs.map +1 -1
  186. package/dist/data/test-runner/TestFailureDetail.d.ts +2 -2
  187. package/dist/data/test-runner/TestFailureDetail.d.ts.map +1 -1
  188. package/dist/data/test-runner/TestFailureDetail.js +23 -27
  189. package/dist/data/test-runner/TestFailureDetail.js.map +1 -1
  190. package/dist/data/test-runner/TestFilterBar.cjs +87 -93
  191. package/dist/data/test-runner/TestFilterBar.cjs.map +1 -1
  192. package/dist/data/test-runner/TestFilterBar.d.ts +3 -2
  193. package/dist/data/test-runner/TestFilterBar.d.ts.map +1 -1
  194. package/dist/data/test-runner/TestFilterBar.js +89 -95
  195. package/dist/data/test-runner/TestFilterBar.js.map +1 -1
  196. package/dist/data/test-runner/TestRunSummary.cjs +35 -21
  197. package/dist/data/test-runner/TestRunSummary.cjs.map +1 -1
  198. package/dist/data/test-runner/TestRunSummary.d.ts.map +1 -1
  199. package/dist/data/test-runner/TestRunSummary.js +35 -21
  200. package/dist/data/test-runner/TestRunSummary.js.map +1 -1
  201. package/dist/data/test-runner/TestRunner.cjs +52 -30
  202. package/dist/data/test-runner/TestRunner.cjs.map +1 -1
  203. package/dist/data/test-runner/TestRunner.d.ts +3 -2
  204. package/dist/data/test-runner/TestRunner.d.ts.map +1 -1
  205. package/dist/data/test-runner/TestRunner.js +52 -30
  206. package/dist/data/test-runner/TestRunner.js.map +1 -1
  207. package/dist/data/test-runner/TestTree.cjs +5 -2
  208. package/dist/data/test-runner/TestTree.cjs.map +1 -1
  209. package/dist/data/test-runner/TestTree.d.ts +5 -2
  210. package/dist/data/test-runner/TestTree.d.ts.map +1 -1
  211. package/dist/data/test-runner/TestTree.js +5 -2
  212. package/dist/data/test-runner/TestTree.js.map +1 -1
  213. package/dist/data/test-runner/TestTreeNode.cjs +27 -19
  214. package/dist/data/test-runner/TestTreeNode.cjs.map +1 -1
  215. package/dist/data/test-runner/TestTreeNode.d.ts.map +1 -1
  216. package/dist/data/test-runner/TestTreeNode.js +28 -20
  217. package/dist/data/test-runner/TestTreeNode.js.map +1 -1
  218. package/dist/data/test-runner/adapter.cjs +11 -0
  219. package/dist/data/test-runner/adapter.cjs.map +1 -1
  220. package/dist/data/test-runner/adapter.d.ts +18 -7
  221. package/dist/data/test-runner/adapter.d.ts.map +1 -1
  222. package/dist/data/test-runner/adapter.js +11 -0
  223. package/dist/data/test-runner/adapter.js.map +1 -1
  224. package/dist/data/test-runner/copy.cjs +114 -0
  225. package/dist/data/test-runner/copy.cjs.map +1 -0
  226. package/dist/data/test-runner/copy.d.ts +47 -0
  227. package/dist/data/test-runner/copy.d.ts.map +1 -0
  228. package/dist/data/test-runner/copy.js +114 -0
  229. package/dist/data/test-runner/copy.js.map +1 -0
  230. package/dist/data/test-runner/index.d.ts +5 -2
  231. package/dist/data/test-runner/index.d.ts.map +1 -1
  232. package/dist/data/test-runner/marks.cjs +143 -0
  233. package/dist/data/test-runner/marks.cjs.map +1 -0
  234. package/dist/data/test-runner/marks.d.ts +30 -0
  235. package/dist/data/test-runner/marks.d.ts.map +1 -0
  236. package/dist/data/test-runner/marks.js +143 -0
  237. package/dist/data/test-runner/marks.js.map +1 -0
  238. package/dist/data/test-runner/status.cjs +27 -44
  239. package/dist/data/test-runner/status.cjs.map +1 -1
  240. package/dist/data/test-runner/status.d.ts +12 -3
  241. package/dist/data/test-runner/status.d.ts.map +1 -1
  242. package/dist/data/test-runner/status.js +27 -44
  243. package/dist/data/test-runner/status.js.map +1 -1
  244. package/dist/data/verification/adapterViews.cjs +16 -41
  245. package/dist/data/verification/adapterViews.cjs.map +1 -1
  246. package/dist/data/verification/adapterViews.d.ts.map +1 -1
  247. package/dist/data/verification/adapterViews.js +16 -41
  248. package/dist/data/verification/adapterViews.js.map +1 -1
  249. package/dist/data/verification/adapters.cjs +115 -3
  250. package/dist/data/verification/adapters.cjs.map +1 -1
  251. package/dist/data/verification/adapters.d.ts.map +1 -1
  252. package/dist/data/verification/adapters.js +115 -3
  253. package/dist/data/verification/adapters.js.map +1 -1
  254. package/dist/data/verification/verifyReportTests.cjs.map +1 -1
  255. package/dist/data/verification/verifyReportTests.js.map +1 -1
  256. package/dist/data/version-info.cjs +3 -3
  257. package/dist/data/version-info.js +3 -3
  258. package/dist/data.cjs +44 -3
  259. package/dist/data.cjs.map +1 -1
  260. package/dist/data.d.ts +2 -0
  261. package/dist/data.d.ts.map +1 -1
  262. package/dist/data.js +45 -4
  263. package/dist/data.js.map +1 -1
  264. package/dist/icons/components/UiLogoEslint.cjs +10 -0
  265. package/dist/icons/components/UiLogoEslint.cjs.map +1 -0
  266. package/dist/icons/components/UiLogoEslint.d.ts +9 -0
  267. package/dist/icons/components/UiLogoEslint.d.ts.map +1 -0
  268. package/dist/icons/components/UiLogoEslint.js +10 -0
  269. package/dist/icons/components/UiLogoEslint.js.map +1 -0
  270. package/dist/icons/components/UiLogoGo.cjs +10 -0
  271. package/dist/icons/components/UiLogoGo.cjs.map +1 -0
  272. package/dist/icons/components/UiLogoGo.d.ts +9 -0
  273. package/dist/icons/components/UiLogoGo.d.ts.map +1 -0
  274. package/dist/icons/components/UiLogoGo.js +10 -0
  275. package/dist/icons/components/UiLogoGo.js.map +1 -0
  276. package/dist/icons/components/UiLogoJest.cjs +10 -0
  277. package/dist/icons/components/UiLogoJest.cjs.map +1 -0
  278. package/dist/icons/components/UiLogoJest.d.ts +9 -0
  279. package/dist/icons/components/UiLogoJest.d.ts.map +1 -0
  280. package/dist/icons/components/UiLogoJest.js +10 -0
  281. package/dist/icons/components/UiLogoJest.js.map +1 -0
  282. package/dist/icons/components/UiLogoMarkdown.cjs +10 -0
  283. package/dist/icons/components/UiLogoMarkdown.cjs.map +1 -0
  284. package/dist/icons/components/UiLogoMarkdown.d.ts +9 -0
  285. package/dist/icons/components/UiLogoMarkdown.d.ts.map +1 -0
  286. package/dist/icons/components/UiLogoMarkdown.js +10 -0
  287. package/dist/icons/components/UiLogoMarkdown.js.map +1 -0
  288. package/dist/icons/components/UiLogoOxc.cjs +10 -0
  289. package/dist/icons/components/UiLogoOxc.cjs.map +1 -0
  290. package/dist/icons/components/UiLogoOxc.d.ts +9 -0
  291. package/dist/icons/components/UiLogoOxc.d.ts.map +1 -0
  292. package/dist/icons/components/UiLogoOxc.js +10 -0
  293. package/dist/icons/components/UiLogoOxc.js.map +1 -0
  294. package/dist/icons/components/UiLogoPlaywright.cjs +10 -0
  295. package/dist/icons/components/UiLogoPlaywright.cjs.map +1 -0
  296. package/dist/icons/components/UiLogoPlaywright.d.ts +9 -0
  297. package/dist/icons/components/UiLogoPlaywright.d.ts.map +1 -0
  298. package/dist/icons/components/UiLogoPlaywright.js +10 -0
  299. package/dist/icons/components/UiLogoPlaywright.js.map +1 -0
  300. package/dist/icons/components/UiLogoPython.cjs +10 -0
  301. package/dist/icons/components/UiLogoPython.cjs.map +1 -0
  302. package/dist/icons/components/UiLogoPython.d.ts +9 -0
  303. package/dist/icons/components/UiLogoPython.d.ts.map +1 -0
  304. package/dist/icons/components/UiLogoPython.js +10 -0
  305. package/dist/icons/components/UiLogoPython.js.map +1 -0
  306. package/dist/icons/components/UiLogoReact.cjs +10 -0
  307. package/dist/icons/components/UiLogoReact.cjs.map +1 -0
  308. package/dist/icons/components/UiLogoReact.d.ts +9 -0
  309. package/dist/icons/components/UiLogoReact.d.ts.map +1 -0
  310. package/dist/icons/components/UiLogoReact.js +10 -0
  311. package/dist/icons/components/UiLogoReact.js.map +1 -0
  312. package/dist/icons/components/UiLogoRuff.cjs +10 -0
  313. package/dist/icons/components/UiLogoRuff.cjs.map +1 -0
  314. package/dist/icons/components/UiLogoRuff.d.ts +9 -0
  315. package/dist/icons/components/UiLogoRuff.d.ts.map +1 -0
  316. package/dist/icons/components/UiLogoRuff.js +10 -0
  317. package/dist/icons/components/UiLogoRuff.js.map +1 -0
  318. package/dist/icons/components/UiLogoTypescript.cjs +10 -0
  319. package/dist/icons/components/UiLogoTypescript.cjs.map +1 -0
  320. package/dist/icons/components/UiLogoTypescript.d.ts +9 -0
  321. package/dist/icons/components/UiLogoTypescript.d.ts.map +1 -0
  322. package/dist/icons/components/UiLogoTypescript.js +10 -0
  323. package/dist/icons/components/UiLogoTypescript.js.map +1 -0
  324. package/dist/icons/components/UiLogoVitest.cjs +10 -0
  325. package/dist/icons/components/UiLogoVitest.cjs.map +1 -0
  326. package/dist/icons/components/UiLogoVitest.d.ts +9 -0
  327. package/dist/icons/components/UiLogoVitest.d.ts.map +1 -0
  328. package/dist/icons/components/UiLogoVitest.js +10 -0
  329. package/dist/icons/components/UiLogoVitest.js.map +1 -0
  330. package/dist/icons/index.d.ts +11 -0
  331. package/dist/icons/index.d.ts.map +1 -1
  332. package/dist/icons/registry.cjs +22 -0
  333. package/dist/icons/registry.cjs.map +1 -1
  334. package/dist/icons/registry.d.ts.map +1 -1
  335. package/dist/icons/registry.js +22 -0
  336. package/dist/icons/registry.js.map +1 -1
  337. package/dist/icons.cjs +22 -0
  338. package/dist/icons.cjs.map +1 -1
  339. package/dist/icons.js +22 -0
  340. package/dist/icons.js.map +1 -1
  341. package/dist/index.cjs +44 -3
  342. package/dist/index.cjs.map +1 -1
  343. package/dist/index.js +45 -4
  344. package/dist/index.js.map +1 -1
  345. package/dist/overlay/DropdownMenuSubmenu.cjs +4 -4
  346. package/dist/overlay/DropdownMenuSubmenu.cjs.map +1 -1
  347. package/dist/overlay/DropdownMenuSubmenu.js +4 -4
  348. package/dist/overlay/DropdownMenuSubmenu.js.map +1 -1
  349. package/dist/rpc/InlineError.cjs +12 -43
  350. package/dist/rpc/InlineError.cjs.map +1 -1
  351. package/dist/rpc/InlineError.d.ts.map +1 -1
  352. package/dist/rpc/InlineError.js +13 -44
  353. package/dist/rpc/InlineError.js.map +1 -1
  354. package/dist/rpc/OperationScheduleDialog.cjs +63 -10
  355. package/dist/rpc/OperationScheduleDialog.cjs.map +1 -1
  356. package/dist/rpc/OperationScheduleDialog.d.ts +4 -0
  357. package/dist/rpc/OperationScheduleDialog.d.ts.map +1 -1
  358. package/dist/rpc/OperationScheduleDialog.js +63 -10
  359. package/dist/rpc/OperationScheduleDialog.js.map +1 -1
  360. package/dist/rpc/OperationSchedules.cjs +12 -2
  361. package/dist/rpc/OperationSchedules.cjs.map +1 -1
  362. package/dist/rpc/OperationSchedules.d.ts.map +1 -1
  363. package/dist/rpc/OperationSchedules.js +12 -2
  364. package/dist/rpc/OperationSchedules.js.map +1 -1
  365. package/dist/rpc/operation-schedule-model.cjs +2 -0
  366. package/dist/rpc/operation-schedule-model.cjs.map +1 -1
  367. package/dist/rpc/operation-schedule-model.d.ts.map +1 -1
  368. package/dist/rpc/operation-schedule-model.js +2 -0
  369. package/dist/rpc/operation-schedule-model.js.map +1 -1
  370. package/dist/rpc/operation-schedule-types.d.ts +7 -1
  371. package/dist/rpc/operation-schedule-types.d.ts.map +1 -1
  372. package/dist/styles.css +1 -1
  373. package/package.json +1 -1
  374. package/dist/data/test-runner/frameworkIcon.cjs +0 -27
  375. package/dist/data/test-runner/frameworkIcon.cjs.map +0 -1
  376. package/dist/data/test-runner/frameworkIcon.d.ts +0 -3
  377. package/dist/data/test-runner/frameworkIcon.d.ts.map +0 -1
  378. package/dist/data/test-runner/frameworkIcon.js +0 -27
  379. package/dist/data/test-runner/frameworkIcon.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.cjs","sources":["../../../src/data/test-runner/adapter.ts"],"sourcesContent":["// Node adapters let a host plug domain-specific rendering into the test runner\n// without forking it. An adapter claims nodes via `match` and contributes how\n// they render in each surface (tree row, detail body, detail tabs, header\n// actions). The registry resolves the first matching adapter per surface;\n// surfaces with no match fall back to the runner's built-in default rendering.\n//\n// This formalizes the wrapper-with-an-if-chain pattern hosts use today (e.g.\n// a ResultDetailPane fall-through over domain panels + tab providers + per-step\n// actions) into a registered, composable contract.\n\nimport type { ReactNode } from \"react\";\nimport type { Test } from \"./types\";\nimport type { TestRunnerContext } from \"./context\";\n\nexport type AdapterContext = {\n node: Test;\n runner: TestRunnerContext;\n};\n\nexport type DetailTab = {\n id: string;\n label: string;\n render: () => ReactNode;\n};\n\nexport type TestNodeAdapter = {\n /** Stable identifier, used as a React key and for debugging. */\n id: string;\n /** Claim the node. The first registered adapter to return true wins per surface. */\n match: (node: Test, runner: TestRunnerContext) => boolean;\n /**\n * Replace the framework icon for the node — return any node (e.g. a brand\n * logo via the host's own icon provider) or null to fall back to the built-in\n * `frameworkIcon`. Lets hosts restore devicon/logos glyphs without clicky\n * depending on a runtime icon provider.\n */\n renderFrameworkIcon?: (c: AdapterContext) => ReactNode;\n /** Extra decoration rendered between the framework icon and the node name. */\n renderRowLeading?: (c: AdapterContext) => ReactNode;\n /** Primary detail body for the node, replacing the default panel body. */\n renderDetail?: (c: AdapterContext) => ReactNode;\n /** Extra detail tabs, merged (in registration order) across all matching adapters. */\n detailTabs?: (c: AdapterContext) => DetailTab[];\n /** Node-scoped action buttons rendered in the detail header. */\n nodeActions?: (c: AdapterContext) => ReactNode;\n /**\n * Whether `renderDetail` owns its own full-height scroll container. When\n * false (the default for custom bodies), the panel wraps it in a scroll\n * region. The built-in default body owns its scroll.\n */\n ownsScroll?: (c: AdapterContext) => boolean;\n};\n\n/**\n * Ordered set of node adapters. First match wins per surface; `detailTabs` are\n * the exception — they merge across every matching adapter so independent\n * adapters can each contribute a tab.\n */\nexport class TestNodeAdapterRegistry {\n readonly adapters: TestNodeAdapter[];\n\n constructor(adapters: TestNodeAdapter[] = []) {\n this.adapters = adapters;\n }\n\n private firstWith(\n node: Test,\n runner: TestRunnerContext,\n has: (a: TestNodeAdapter) => boolean,\n ): TestNodeAdapter | null {\n for (const a of this.adapters) {\n if (has(a) && a.match(node, runner)) return a;\n }\n return null;\n }\n\n /** Adapter whose `renderDetail` should drive the body, or null for the default. */\n resolveDetail(node: Test, runner: TestRunnerContext): TestNodeAdapter | null {\n return this.firstWith(node, runner, (a) => !!a.renderDetail);\n }\n\n resolveRowLeading(node: Test, runner: TestRunnerContext): TestNodeAdapter | null {\n return this.firstWith(node, runner, (a) => !!a.renderRowLeading);\n }\n\n resolveFrameworkIcon(node: Test, runner: TestRunnerContext): TestNodeAdapter | null {\n return this.firstWith(node, runner, (a) => !!a.renderFrameworkIcon);\n }\n\n resolveActions(node: Test, runner: TestRunnerContext): TestNodeAdapter | null {\n return this.firstWith(node, runner, (a) => !!a.nodeActions);\n }\n\n /** Merge `detailTabs` from every matching adapter, de-duplicated by tab id. */\n resolveTabs(node: Test, runner: TestRunnerContext): DetailTab[] {\n const ctx: AdapterContext = { node, runner };\n const seen = new Set<string>();\n const tabs: DetailTab[] = [];\n for (const a of this.adapters) {\n if (!a.detailTabs || !a.match(node, runner)) continue;\n for (const tab of a.detailTabs(ctx)) {\n if (seen.has(tab.id)) continue;\n seen.add(tab.id);\n tabs.push(tab);\n }\n }\n return tabs;\n }\n\n /** True when the resolved detail adapter owns its own scroll region. */\n ownsScroll(node: Test, runner: TestRunnerContext): boolean {\n const a = this.resolveDetail(node, runner);\n if (!a?.ownsScroll) return false;\n return a.ownsScroll({ node, runner });\n }\n}\n\nexport function createTestRunnerRegistry(\n adapters: TestNodeAdapter[] = [],\n): TestNodeAdapterRegistry {\n return new TestNodeAdapterRegistry(adapters);\n}\n"],"names":[],"mappings":";;;;;AA0DO,MAAM,wBAAwB;AAAA,EAGnC,YAAY,WAA8B,IAAI;AAFrC;AAGP,SAAK,WAAW;AAAA,EAClB;AAAA,EAEQ,UACN,MACA,QACA,KACwB;AACxB,eAAW,KAAK,KAAK,UAAU;AAC7B,UAAI,IAAI,CAAC,KAAK,EAAE,MAAM,MAAM,MAAM,EAAG,QAAO;AAAA,IAC9C;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,cAAc,MAAY,QAAmD;AAC3E,WAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,YAAY;AAAA,EAC7D;AAAA,EAEA,kBAAkB,MAAY,QAAmD;AAC/E,WAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,gBAAgB;AAAA,EACjE;AAAA,EAEA,qBAAqB,MAAY,QAAmD;AAClF,WAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,mBAAmB;AAAA,EACpE;AAAA,EAEA,eAAe,MAAY,QAAmD;AAC5E,WAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW;AAAA,EAC5D;AAAA;AAAA,EAGA,YAAY,MAAY,QAAwC;AAC9D,UAAM,MAAsB,EAAE,MAAM,OAAA;AACpC,UAAM,2BAAW,IAAA;AACjB,UAAM,OAAoB,CAAA;AAC1B,eAAW,KAAK,KAAK,UAAU;AAC7B,UAAI,CAAC,EAAE,cAAc,CAAC,EAAE,MAAM,MAAM,MAAM,EAAG;AAC7C,iBAAW,OAAO,EAAE,WAAW,GAAG,GAAG;AACnC,YAAI,KAAK,IAAI,IAAI,EAAE,EAAG;AACtB,aAAK,IAAI,IAAI,EAAE;AACf,aAAK,KAAK,GAAG;AAAA,MACf;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,WAAW,MAAY,QAAoC;AACzD,UAAM,IAAI,KAAK,cAAc,MAAM,MAAM;AACzC,QAAI,EAAC,uBAAG,YAAY,QAAO;AAC3B,WAAO,EAAE,WAAW,EAAE,MAAM,QAAQ;AAAA,EACtC;AACF;AAEO,SAAS,yBACd,WAA8B,IACL;AACzB,SAAO,IAAI,wBAAwB,QAAQ;AAC7C;;;"}
1
+ {"version":3,"file":"adapter.cjs","sources":["../../../src/data/test-runner/adapter.ts"],"sourcesContent":["// Node adapters let a host plug domain-specific rendering into the test runner\n// without forking it. An adapter claims nodes via `match` and contributes how\n// they render in each surface (tree row, detail body, detail tabs, header\n// actions). The registry resolves the first matching adapter per surface;\n// surfaces with no match fall back to the runner's built-in default rendering.\n//\n// This formalizes the wrapper-with-an-if-chain pattern hosts use today (e.g.\n// a ResultDetailPane fall-through over domain panels + tab providers + per-step\n// actions) into a registered, composable contract.\n\nimport type { ReactNode } from \"react\";\nimport type { Test } from \"./types\";\nimport type { TestRunnerContext } from \"./context\";\nimport { mergeCopySections, type CopySections } from \"./copy\";\n\nexport type AdapterContext = {\n node: Test;\n runner: TestRunnerContext;\n};\n\nexport type DetailTab = {\n id: string;\n label: string;\n render: () => ReactNode;\n};\n\nexport type TestNodeAdapter = {\n /** Stable identifier, used as a React key and for debugging. */\n id: string;\n /** Claim the node. The first registered adapter to return true wins per surface. */\n match: (node: Test, runner: TestRunnerContext) => boolean;\n /**\n * Replace the framework icon for the node — return any node, or null to fall\n * back to the built-in tool mark (`TEST_TOOLS`). For a tool the catalog\n * lacks, prefer adding it to `TEST_TOOLS` so every surface shows it.\n */\n renderFrameworkIcon?: (c: AdapterContext) => ReactNode;\n /** Extra decoration rendered between the framework icon and the node name. */\n renderRowLeading?: (c: AdapterContext) => ReactNode;\n /** Primary detail body for the node, replacing the default panel body. */\n renderDetail?: (c: AdapterContext) => ReactNode;\n /** Extra detail tabs, merged (in registration order) across all matching adapters. */\n detailTabs?: (c: AdapterContext) => DetailTab[];\n /** Node-scoped action buttons rendered in the detail header. */\n nodeActions?: (c: AdapterContext) => ReactNode;\n /**\n * Domain facts, brief sections and menu items for the header's \"Copy details\"\n * button, merged (in registration order) across all matching adapters on top\n * of the generic sections every node gets.\n */\n copy?: (c: AdapterContext) => CopySections;\n /**\n * Whether `renderDetail` owns its own full-height scroll container. When\n * false (the default for custom bodies), the panel wraps it in a scroll\n * region. The built-in default body owns its scroll.\n */\n ownsScroll?: (c: AdapterContext) => boolean;\n};\n\n/**\n * Ordered set of node adapters. First match wins per surface; `detailTabs` and\n * `copy` are the exceptions — they merge across every matching adapter so\n * independent adapters can each contribute a tab or a copy section.\n */\nexport class TestNodeAdapterRegistry {\n readonly adapters: TestNodeAdapter[];\n\n constructor(adapters: TestNodeAdapter[] = []) {\n this.adapters = adapters;\n }\n\n private firstWith(\n node: Test,\n runner: TestRunnerContext,\n has: (a: TestNodeAdapter) => boolean,\n ): TestNodeAdapter | null {\n for (const a of this.adapters) {\n if (has(a) && a.match(node, runner)) return a;\n }\n return null;\n }\n\n /** Adapter whose `renderDetail` should drive the body, or null for the default. */\n resolveDetail(node: Test, runner: TestRunnerContext): TestNodeAdapter | null {\n return this.firstWith(node, runner, (a) => !!a.renderDetail);\n }\n\n resolveRowLeading(node: Test, runner: TestRunnerContext): TestNodeAdapter | null {\n return this.firstWith(node, runner, (a) => !!a.renderRowLeading);\n }\n\n resolveFrameworkIcon(node: Test, runner: TestRunnerContext): TestNodeAdapter | null {\n return this.firstWith(node, runner, (a) => !!a.renderFrameworkIcon);\n }\n\n resolveActions(node: Test, runner: TestRunnerContext): TestNodeAdapter | null {\n return this.firstWith(node, runner, (a) => !!a.nodeActions);\n }\n\n /** Merge `detailTabs` from every matching adapter, de-duplicated by tab id. */\n resolveTabs(node: Test, runner: TestRunnerContext): DetailTab[] {\n const ctx: AdapterContext = { node, runner };\n const seen = new Set<string>();\n const tabs: DetailTab[] = [];\n for (const a of this.adapters) {\n if (!a.detailTabs || !a.match(node, runner)) continue;\n for (const tab of a.detailTabs(ctx)) {\n if (seen.has(tab.id)) continue;\n seen.add(tab.id);\n tabs.push(tab);\n }\n }\n return tabs;\n }\n\n /**\n * Merge `copy` sections from every matching adapter, de-duplicated by fact\n * label, section title and item label — the first contributor wins.\n */\n resolveCopy(node: Test, runner: TestRunnerContext): Required<CopySections> {\n const ctx: AdapterContext = { node, runner };\n return mergeCopySections(\n this.adapters.flatMap((a) => (a.copy && a.match(node, runner) ? [a.copy(ctx)] : [])),\n );\n }\n\n /** True when the resolved detail adapter owns its own scroll region. */\n ownsScroll(node: Test, runner: TestRunnerContext): boolean {\n const a = this.resolveDetail(node, runner);\n if (!a?.ownsScroll) return false;\n return a.ownsScroll({ node, runner });\n }\n}\n\nexport function createTestRunnerRegistry(\n adapters: TestNodeAdapter[] = [],\n): TestNodeAdapterRegistry {\n return new TestNodeAdapterRegistry(adapters);\n}\n"],"names":["mergeCopySections"],"mappings":";;;;;;AAgEO,MAAM,wBAAwB;AAAA,EAGnC,YAAY,WAA8B,IAAI;AAFrC;AAGP,SAAK,WAAW;AAAA,EAClB;AAAA,EAEQ,UACN,MACA,QACA,KACwB;AACxB,eAAW,KAAK,KAAK,UAAU;AAC7B,UAAI,IAAI,CAAC,KAAK,EAAE,MAAM,MAAM,MAAM,EAAG,QAAO;AAAA,IAC9C;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,cAAc,MAAY,QAAmD;AAC3E,WAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,YAAY;AAAA,EAC7D;AAAA,EAEA,kBAAkB,MAAY,QAAmD;AAC/E,WAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,gBAAgB;AAAA,EACjE;AAAA,EAEA,qBAAqB,MAAY,QAAmD;AAClF,WAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,mBAAmB;AAAA,EACpE;AAAA,EAEA,eAAe,MAAY,QAAmD;AAC5E,WAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW;AAAA,EAC5D;AAAA;AAAA,EAGA,YAAY,MAAY,QAAwC;AAC9D,UAAM,MAAsB,EAAE,MAAM,OAAA;AACpC,UAAM,2BAAW,IAAA;AACjB,UAAM,OAAoB,CAAA;AAC1B,eAAW,KAAK,KAAK,UAAU;AAC7B,UAAI,CAAC,EAAE,cAAc,CAAC,EAAE,MAAM,MAAM,MAAM,EAAG;AAC7C,iBAAW,OAAO,EAAE,WAAW,GAAG,GAAG;AACnC,YAAI,KAAK,IAAI,IAAI,EAAE,EAAG;AACtB,aAAK,IAAI,IAAI,EAAE;AACf,aAAK,KAAK,GAAG;AAAA,MACf;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,MAAY,QAAmD;AACzE,UAAM,MAAsB,EAAE,MAAM,OAAA;AACpC,WAAOA,KAAAA;AAAAA,MACL,KAAK,SAAS,QAAQ,CAAC,MAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,MAAM,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,IAAI,CAAA,CAAG;AAAA,IAAA;AAAA,EAEvF;AAAA;AAAA,EAGA,WAAW,MAAY,QAAoC;AACzD,UAAM,IAAI,KAAK,cAAc,MAAM,MAAM;AACzC,QAAI,EAAC,uBAAG,YAAY,QAAO;AAC3B,WAAO,EAAE,WAAW,EAAE,MAAM,QAAQ;AAAA,EACtC;AACF;AAEO,SAAS,yBACd,WAA8B,IACL;AACzB,SAAO,IAAI,wBAAwB,QAAQ;AAC7C;;;"}
@@ -1,6 +1,7 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { Test } from './types.js';
3
3
  import { TestRunnerContext } from './context.js';
4
+ import { CopySections } from './copy.js';
4
5
  export type AdapterContext = {
5
6
  node: Test;
6
7
  runner: TestRunnerContext;
@@ -16,10 +17,9 @@ export type TestNodeAdapter = {
16
17
  /** Claim the node. The first registered adapter to return true wins per surface. */
17
18
  match: (node: Test, runner: TestRunnerContext) => boolean;
18
19
  /**
19
- * Replace the framework icon for the node — return any node (e.g. a brand
20
- * logo via the host's own icon provider) or null to fall back to the built-in
21
- * `frameworkIcon`. Lets hosts restore devicon/logos glyphs without clicky
22
- * depending on a runtime icon provider.
20
+ * Replace the framework icon for the node — return any node, or null to fall
21
+ * back to the built-in tool mark (`TEST_TOOLS`). For a tool the catalog
22
+ * lacks, prefer adding it to `TEST_TOOLS` so every surface shows it.
23
23
  */
24
24
  renderFrameworkIcon?: (c: AdapterContext) => ReactNode;
25
25
  /** Extra decoration rendered between the framework icon and the node name. */
@@ -30,6 +30,12 @@ export type TestNodeAdapter = {
30
30
  detailTabs?: (c: AdapterContext) => DetailTab[];
31
31
  /** Node-scoped action buttons rendered in the detail header. */
32
32
  nodeActions?: (c: AdapterContext) => ReactNode;
33
+ /**
34
+ * Domain facts, brief sections and menu items for the header's "Copy details"
35
+ * button, merged (in registration order) across all matching adapters on top
36
+ * of the generic sections every node gets.
37
+ */
38
+ copy?: (c: AdapterContext) => CopySections;
33
39
  /**
34
40
  * Whether `renderDetail` owns its own full-height scroll container. When
35
41
  * false (the default for custom bodies), the panel wraps it in a scroll
@@ -38,9 +44,9 @@ export type TestNodeAdapter = {
38
44
  ownsScroll?: (c: AdapterContext) => boolean;
39
45
  };
40
46
  /**
41
- * Ordered set of node adapters. First match wins per surface; `detailTabs` are
42
- * the exception — they merge across every matching adapter so independent
43
- * adapters can each contribute a tab.
47
+ * Ordered set of node adapters. First match wins per surface; `detailTabs` and
48
+ * `copy` are the exceptions — they merge across every matching adapter so
49
+ * independent adapters can each contribute a tab or a copy section.
44
50
  */
45
51
  export declare class TestNodeAdapterRegistry {
46
52
  readonly adapters: TestNodeAdapter[];
@@ -53,6 +59,11 @@ export declare class TestNodeAdapterRegistry {
53
59
  resolveActions(node: Test, runner: TestRunnerContext): TestNodeAdapter | null;
54
60
  /** Merge `detailTabs` from every matching adapter, de-duplicated by tab id. */
55
61
  resolveTabs(node: Test, runner: TestRunnerContext): DetailTab[];
62
+ /**
63
+ * Merge `copy` sections from every matching adapter, de-duplicated by fact
64
+ * label, section title and item label — the first contributor wins.
65
+ */
66
+ resolveCopy(node: Test, runner: TestRunnerContext): Required<CopySections>;
56
67
  /** True when the resolved detail adapter owns its own scroll region. */
57
68
  ownsScroll(node: Test, runner: TestRunnerContext): boolean;
58
69
  }
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/adapter.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,iBAAiB,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,SAAS,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,gEAAgE;IAChE,EAAE,EAAE,MAAM,CAAC;IACX,oFAAoF;IACpF,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,KAAK,OAAO,CAAC;IAC1D;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,SAAS,CAAC;IACvD,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,SAAS,CAAC;IACpD,0EAA0E;IAC1E,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,SAAS,CAAC;IAChD,sFAAsF;IACtF,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,SAAS,EAAE,CAAC;IAChD,gEAAgE;IAChE,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,SAAS,CAAC;IAC/C;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC;CAC7C,CAAC;AAEF;;;;GAIG;AACH,qBAAa,uBAAuB;IAClC,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;gBAEzB,QAAQ,GAAE,eAAe,EAAO;IAI5C,OAAO,CAAC,SAAS;IAWjB,mFAAmF;IACnF,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,GAAG,eAAe,GAAG,IAAI;IAI5E,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,GAAG,eAAe,GAAG,IAAI;IAIhF,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,GAAG,eAAe,GAAG,IAAI;IAInF,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,GAAG,eAAe,GAAG,IAAI;IAI7E,+EAA+E;IAC/E,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,GAAG,SAAS,EAAE;IAe/D,wEAAwE;IACxE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO;CAK3D;AAED,wBAAgB,wBAAwB,CACtC,QAAQ,GAAE,eAAe,EAAO,GAC/B,uBAAuB,CAEzB"}
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/adapter.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,QAAQ,CAAC;AAE9D,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,iBAAiB,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,SAAS,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,gEAAgE;IAChE,EAAE,EAAE,MAAM,CAAC;IACX,oFAAoF;IACpF,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,KAAK,OAAO,CAAC;IAC1D;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,SAAS,CAAC;IACvD,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,SAAS,CAAC;IACpD,0EAA0E;IAC1E,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,SAAS,CAAC;IAChD,sFAAsF;IACtF,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,SAAS,EAAE,CAAC;IAChD,gEAAgE;IAChE,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,SAAS,CAAC;IAC/C;;;;OAIG;IACH,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,YAAY,CAAC;IAC3C;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC;CAC7C,CAAC;AAEF;;;;GAIG;AACH,qBAAa,uBAAuB;IAClC,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;gBAEzB,QAAQ,GAAE,eAAe,EAAO;IAI5C,OAAO,CAAC,SAAS;IAWjB,mFAAmF;IACnF,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,GAAG,eAAe,GAAG,IAAI;IAI5E,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,GAAG,eAAe,GAAG,IAAI;IAIhF,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,GAAG,eAAe,GAAG,IAAI;IAInF,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,GAAG,eAAe,GAAG,IAAI;IAI7E,+EAA+E;IAC/E,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,GAAG,SAAS,EAAE;IAe/D;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,GAAG,QAAQ,CAAC,YAAY,CAAC;IAO1E,wEAAwE;IACxE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO;CAK3D;AAED,wBAAgB,wBAAwB,CACtC,QAAQ,GAAE,eAAe,EAAO,GAC/B,uBAAuB,CAEzB"}
@@ -1,6 +1,7 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+ import { mergeCopySections } from "./copy.js";
4
5
  class TestNodeAdapterRegistry {
5
6
  constructor(adapters = []) {
6
7
  __publicField(this, "adapters");
@@ -40,6 +41,16 @@ class TestNodeAdapterRegistry {
40
41
  }
41
42
  return tabs;
42
43
  }
44
+ /**
45
+ * Merge `copy` sections from every matching adapter, de-duplicated by fact
46
+ * label, section title and item label — the first contributor wins.
47
+ */
48
+ resolveCopy(node, runner) {
49
+ const ctx = { node, runner };
50
+ return mergeCopySections(
51
+ this.adapters.flatMap((a) => a.copy && a.match(node, runner) ? [a.copy(ctx)] : [])
52
+ );
53
+ }
43
54
  /** True when the resolved detail adapter owns its own scroll region. */
44
55
  ownsScroll(node, runner) {
45
56
  const a = this.resolveDetail(node, runner);
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","sources":["../../../src/data/test-runner/adapter.ts"],"sourcesContent":["// Node adapters let a host plug domain-specific rendering into the test runner\n// without forking it. An adapter claims nodes via `match` and contributes how\n// they render in each surface (tree row, detail body, detail tabs, header\n// actions). The registry resolves the first matching adapter per surface;\n// surfaces with no match fall back to the runner's built-in default rendering.\n//\n// This formalizes the wrapper-with-an-if-chain pattern hosts use today (e.g.\n// a ResultDetailPane fall-through over domain panels + tab providers + per-step\n// actions) into a registered, composable contract.\n\nimport type { ReactNode } from \"react\";\nimport type { Test } from \"./types\";\nimport type { TestRunnerContext } from \"./context\";\n\nexport type AdapterContext = {\n node: Test;\n runner: TestRunnerContext;\n};\n\nexport type DetailTab = {\n id: string;\n label: string;\n render: () => ReactNode;\n};\n\nexport type TestNodeAdapter = {\n /** Stable identifier, used as a React key and for debugging. */\n id: string;\n /** Claim the node. The first registered adapter to return true wins per surface. */\n match: (node: Test, runner: TestRunnerContext) => boolean;\n /**\n * Replace the framework icon for the node — return any node (e.g. a brand\n * logo via the host's own icon provider) or null to fall back to the built-in\n * `frameworkIcon`. Lets hosts restore devicon/logos glyphs without clicky\n * depending on a runtime icon provider.\n */\n renderFrameworkIcon?: (c: AdapterContext) => ReactNode;\n /** Extra decoration rendered between the framework icon and the node name. */\n renderRowLeading?: (c: AdapterContext) => ReactNode;\n /** Primary detail body for the node, replacing the default panel body. */\n renderDetail?: (c: AdapterContext) => ReactNode;\n /** Extra detail tabs, merged (in registration order) across all matching adapters. */\n detailTabs?: (c: AdapterContext) => DetailTab[];\n /** Node-scoped action buttons rendered in the detail header. */\n nodeActions?: (c: AdapterContext) => ReactNode;\n /**\n * Whether `renderDetail` owns its own full-height scroll container. When\n * false (the default for custom bodies), the panel wraps it in a scroll\n * region. The built-in default body owns its scroll.\n */\n ownsScroll?: (c: AdapterContext) => boolean;\n};\n\n/**\n * Ordered set of node adapters. First match wins per surface; `detailTabs` are\n * the exception — they merge across every matching adapter so independent\n * adapters can each contribute a tab.\n */\nexport class TestNodeAdapterRegistry {\n readonly adapters: TestNodeAdapter[];\n\n constructor(adapters: TestNodeAdapter[] = []) {\n this.adapters = adapters;\n }\n\n private firstWith(\n node: Test,\n runner: TestRunnerContext,\n has: (a: TestNodeAdapter) => boolean,\n ): TestNodeAdapter | null {\n for (const a of this.adapters) {\n if (has(a) && a.match(node, runner)) return a;\n }\n return null;\n }\n\n /** Adapter whose `renderDetail` should drive the body, or null for the default. */\n resolveDetail(node: Test, runner: TestRunnerContext): TestNodeAdapter | null {\n return this.firstWith(node, runner, (a) => !!a.renderDetail);\n }\n\n resolveRowLeading(node: Test, runner: TestRunnerContext): TestNodeAdapter | null {\n return this.firstWith(node, runner, (a) => !!a.renderRowLeading);\n }\n\n resolveFrameworkIcon(node: Test, runner: TestRunnerContext): TestNodeAdapter | null {\n return this.firstWith(node, runner, (a) => !!a.renderFrameworkIcon);\n }\n\n resolveActions(node: Test, runner: TestRunnerContext): TestNodeAdapter | null {\n return this.firstWith(node, runner, (a) => !!a.nodeActions);\n }\n\n /** Merge `detailTabs` from every matching adapter, de-duplicated by tab id. */\n resolveTabs(node: Test, runner: TestRunnerContext): DetailTab[] {\n const ctx: AdapterContext = { node, runner };\n const seen = new Set<string>();\n const tabs: DetailTab[] = [];\n for (const a of this.adapters) {\n if (!a.detailTabs || !a.match(node, runner)) continue;\n for (const tab of a.detailTabs(ctx)) {\n if (seen.has(tab.id)) continue;\n seen.add(tab.id);\n tabs.push(tab);\n }\n }\n return tabs;\n }\n\n /** True when the resolved detail adapter owns its own scroll region. */\n ownsScroll(node: Test, runner: TestRunnerContext): boolean {\n const a = this.resolveDetail(node, runner);\n if (!a?.ownsScroll) return false;\n return a.ownsScroll({ node, runner });\n }\n}\n\nexport function createTestRunnerRegistry(\n adapters: TestNodeAdapter[] = [],\n): TestNodeAdapterRegistry {\n return new TestNodeAdapterRegistry(adapters);\n}\n"],"names":[],"mappings":";;;AA0DO,MAAM,wBAAwB;AAAA,EAGnC,YAAY,WAA8B,IAAI;AAFrC;AAGP,SAAK,WAAW;AAAA,EAClB;AAAA,EAEQ,UACN,MACA,QACA,KACwB;AACxB,eAAW,KAAK,KAAK,UAAU;AAC7B,UAAI,IAAI,CAAC,KAAK,EAAE,MAAM,MAAM,MAAM,EAAG,QAAO;AAAA,IAC9C;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,cAAc,MAAY,QAAmD;AAC3E,WAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,YAAY;AAAA,EAC7D;AAAA,EAEA,kBAAkB,MAAY,QAAmD;AAC/E,WAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,gBAAgB;AAAA,EACjE;AAAA,EAEA,qBAAqB,MAAY,QAAmD;AAClF,WAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,mBAAmB;AAAA,EACpE;AAAA,EAEA,eAAe,MAAY,QAAmD;AAC5E,WAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW;AAAA,EAC5D;AAAA;AAAA,EAGA,YAAY,MAAY,QAAwC;AAC9D,UAAM,MAAsB,EAAE,MAAM,OAAA;AACpC,UAAM,2BAAW,IAAA;AACjB,UAAM,OAAoB,CAAA;AAC1B,eAAW,KAAK,KAAK,UAAU;AAC7B,UAAI,CAAC,EAAE,cAAc,CAAC,EAAE,MAAM,MAAM,MAAM,EAAG;AAC7C,iBAAW,OAAO,EAAE,WAAW,GAAG,GAAG;AACnC,YAAI,KAAK,IAAI,IAAI,EAAE,EAAG;AACtB,aAAK,IAAI,IAAI,EAAE;AACf,aAAK,KAAK,GAAG;AAAA,MACf;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,WAAW,MAAY,QAAoC;AACzD,UAAM,IAAI,KAAK,cAAc,MAAM,MAAM;AACzC,QAAI,EAAC,uBAAG,YAAY,QAAO;AAC3B,WAAO,EAAE,WAAW,EAAE,MAAM,QAAQ;AAAA,EACtC;AACF;AAEO,SAAS,yBACd,WAA8B,IACL;AACzB,SAAO,IAAI,wBAAwB,QAAQ;AAC7C;"}
1
+ {"version":3,"file":"adapter.js","sources":["../../../src/data/test-runner/adapter.ts"],"sourcesContent":["// Node adapters let a host plug domain-specific rendering into the test runner\n// without forking it. An adapter claims nodes via `match` and contributes how\n// they render in each surface (tree row, detail body, detail tabs, header\n// actions). The registry resolves the first matching adapter per surface;\n// surfaces with no match fall back to the runner's built-in default rendering.\n//\n// This formalizes the wrapper-with-an-if-chain pattern hosts use today (e.g.\n// a ResultDetailPane fall-through over domain panels + tab providers + per-step\n// actions) into a registered, composable contract.\n\nimport type { ReactNode } from \"react\";\nimport type { Test } from \"./types\";\nimport type { TestRunnerContext } from \"./context\";\nimport { mergeCopySections, type CopySections } from \"./copy\";\n\nexport type AdapterContext = {\n node: Test;\n runner: TestRunnerContext;\n};\n\nexport type DetailTab = {\n id: string;\n label: string;\n render: () => ReactNode;\n};\n\nexport type TestNodeAdapter = {\n /** Stable identifier, used as a React key and for debugging. */\n id: string;\n /** Claim the node. The first registered adapter to return true wins per surface. */\n match: (node: Test, runner: TestRunnerContext) => boolean;\n /**\n * Replace the framework icon for the node — return any node, or null to fall\n * back to the built-in tool mark (`TEST_TOOLS`). For a tool the catalog\n * lacks, prefer adding it to `TEST_TOOLS` so every surface shows it.\n */\n renderFrameworkIcon?: (c: AdapterContext) => ReactNode;\n /** Extra decoration rendered between the framework icon and the node name. */\n renderRowLeading?: (c: AdapterContext) => ReactNode;\n /** Primary detail body for the node, replacing the default panel body. */\n renderDetail?: (c: AdapterContext) => ReactNode;\n /** Extra detail tabs, merged (in registration order) across all matching adapters. */\n detailTabs?: (c: AdapterContext) => DetailTab[];\n /** Node-scoped action buttons rendered in the detail header. */\n nodeActions?: (c: AdapterContext) => ReactNode;\n /**\n * Domain facts, brief sections and menu items for the header's \"Copy details\"\n * button, merged (in registration order) across all matching adapters on top\n * of the generic sections every node gets.\n */\n copy?: (c: AdapterContext) => CopySections;\n /**\n * Whether `renderDetail` owns its own full-height scroll container. When\n * false (the default for custom bodies), the panel wraps it in a scroll\n * region. The built-in default body owns its scroll.\n */\n ownsScroll?: (c: AdapterContext) => boolean;\n};\n\n/**\n * Ordered set of node adapters. First match wins per surface; `detailTabs` and\n * `copy` are the exceptions — they merge across every matching adapter so\n * independent adapters can each contribute a tab or a copy section.\n */\nexport class TestNodeAdapterRegistry {\n readonly adapters: TestNodeAdapter[];\n\n constructor(adapters: TestNodeAdapter[] = []) {\n this.adapters = adapters;\n }\n\n private firstWith(\n node: Test,\n runner: TestRunnerContext,\n has: (a: TestNodeAdapter) => boolean,\n ): TestNodeAdapter | null {\n for (const a of this.adapters) {\n if (has(a) && a.match(node, runner)) return a;\n }\n return null;\n }\n\n /** Adapter whose `renderDetail` should drive the body, or null for the default. */\n resolveDetail(node: Test, runner: TestRunnerContext): TestNodeAdapter | null {\n return this.firstWith(node, runner, (a) => !!a.renderDetail);\n }\n\n resolveRowLeading(node: Test, runner: TestRunnerContext): TestNodeAdapter | null {\n return this.firstWith(node, runner, (a) => !!a.renderRowLeading);\n }\n\n resolveFrameworkIcon(node: Test, runner: TestRunnerContext): TestNodeAdapter | null {\n return this.firstWith(node, runner, (a) => !!a.renderFrameworkIcon);\n }\n\n resolveActions(node: Test, runner: TestRunnerContext): TestNodeAdapter | null {\n return this.firstWith(node, runner, (a) => !!a.nodeActions);\n }\n\n /** Merge `detailTabs` from every matching adapter, de-duplicated by tab id. */\n resolveTabs(node: Test, runner: TestRunnerContext): DetailTab[] {\n const ctx: AdapterContext = { node, runner };\n const seen = new Set<string>();\n const tabs: DetailTab[] = [];\n for (const a of this.adapters) {\n if (!a.detailTabs || !a.match(node, runner)) continue;\n for (const tab of a.detailTabs(ctx)) {\n if (seen.has(tab.id)) continue;\n seen.add(tab.id);\n tabs.push(tab);\n }\n }\n return tabs;\n }\n\n /**\n * Merge `copy` sections from every matching adapter, de-duplicated by fact\n * label, section title and item label — the first contributor wins.\n */\n resolveCopy(node: Test, runner: TestRunnerContext): Required<CopySections> {\n const ctx: AdapterContext = { node, runner };\n return mergeCopySections(\n this.adapters.flatMap((a) => (a.copy && a.match(node, runner) ? [a.copy(ctx)] : [])),\n );\n }\n\n /** True when the resolved detail adapter owns its own scroll region. */\n ownsScroll(node: Test, runner: TestRunnerContext): boolean {\n const a = this.resolveDetail(node, runner);\n if (!a?.ownsScroll) return false;\n return a.ownsScroll({ node, runner });\n }\n}\n\nexport function createTestRunnerRegistry(\n adapters: TestNodeAdapter[] = [],\n): TestNodeAdapterRegistry {\n return new TestNodeAdapterRegistry(adapters);\n}\n"],"names":[],"mappings":";;;;AAgEO,MAAM,wBAAwB;AAAA,EAGnC,YAAY,WAA8B,IAAI;AAFrC;AAGP,SAAK,WAAW;AAAA,EAClB;AAAA,EAEQ,UACN,MACA,QACA,KACwB;AACxB,eAAW,KAAK,KAAK,UAAU;AAC7B,UAAI,IAAI,CAAC,KAAK,EAAE,MAAM,MAAM,MAAM,EAAG,QAAO;AAAA,IAC9C;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,cAAc,MAAY,QAAmD;AAC3E,WAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,YAAY;AAAA,EAC7D;AAAA,EAEA,kBAAkB,MAAY,QAAmD;AAC/E,WAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,gBAAgB;AAAA,EACjE;AAAA,EAEA,qBAAqB,MAAY,QAAmD;AAClF,WAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,mBAAmB;AAAA,EACpE;AAAA,EAEA,eAAe,MAAY,QAAmD;AAC5E,WAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW;AAAA,EAC5D;AAAA;AAAA,EAGA,YAAY,MAAY,QAAwC;AAC9D,UAAM,MAAsB,EAAE,MAAM,OAAA;AACpC,UAAM,2BAAW,IAAA;AACjB,UAAM,OAAoB,CAAA;AAC1B,eAAW,KAAK,KAAK,UAAU;AAC7B,UAAI,CAAC,EAAE,cAAc,CAAC,EAAE,MAAM,MAAM,MAAM,EAAG;AAC7C,iBAAW,OAAO,EAAE,WAAW,GAAG,GAAG;AACnC,YAAI,KAAK,IAAI,IAAI,EAAE,EAAG;AACtB,aAAK,IAAI,IAAI,EAAE;AACf,aAAK,KAAK,GAAG;AAAA,MACf;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,MAAY,QAAmD;AACzE,UAAM,MAAsB,EAAE,MAAM,OAAA;AACpC,WAAO;AAAA,MACL,KAAK,SAAS,QAAQ,CAAC,MAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,MAAM,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,IAAI,CAAA,CAAG;AAAA,IAAA;AAAA,EAEvF;AAAA;AAAA,EAGA,WAAW,MAAY,QAAoC;AACzD,UAAM,IAAI,KAAK,cAAc,MAAM,MAAM;AACzC,QAAI,EAAC,uBAAG,YAAY,QAAO;AAC3B,WAAO,EAAE,WAAW,EAAE,MAAM,QAAQ;AAAA,EACtC;AACF;AAEO,SAAS,yBACd,WAA8B,IACL;AACzB,SAAO,IAAI,wBAAwB,QAAQ;AAC7C;"}
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const status = require("./status.cjs");
4
+ const OUTPUT_TITLES = /* @__PURE__ */ new Set(["stdout", "stderr"]);
5
+ function fact(label, value) {
6
+ return value ? [{ label, value }] : [];
7
+ }
8
+ function section(title, body, lang) {
9
+ if (!body) return [];
10
+ return [lang ? { title, lang, body } : { title, body }];
11
+ }
12
+ function nodeLocation(node) {
13
+ if (!node.file) return void 0;
14
+ return node.line ? `${node.file}:${node.line}` : node.file;
15
+ }
16
+ function errorBody(node) {
17
+ var _a;
18
+ const summary = (_a = node.failure_detail) == null ? void 0 : _a.summary;
19
+ const lines = [node.message, summary !== node.message ? summary : void 0];
20
+ return lines.filter(Boolean).join("\n");
21
+ }
22
+ function expectationBody(node) {
23
+ const failure = node.failure_detail;
24
+ if (!failure) return "";
25
+ return [
26
+ failure.matcher && `matcher: ${failure.matcher}`,
27
+ failure.expected && `expected: ${failure.expected}`,
28
+ failure.actual && `actual: ${failure.actual}`,
29
+ failure.location && `at: ${failure.location}`
30
+ ].filter(Boolean).join("\n");
31
+ }
32
+ function genericCopySections(node) {
33
+ var _a;
34
+ const duration = node.duration ? status.formatTestDuration(node.duration) : void 0;
35
+ return {
36
+ facts: [
37
+ ...fact("Result", status.outcomeFor(node) ?? void 0),
38
+ ...fact("Tool", node.framework),
39
+ ...fact("Location", nodeLocation(node)),
40
+ ...fact("Duration", duration)
41
+ ],
42
+ brief: [
43
+ ...section("Error", errorBody(node)),
44
+ ...section("Expectation", expectationBody(node)),
45
+ ...section("Stack", (_a = node.failure_detail) == null ? void 0 : _a.stack),
46
+ ...section("stdout", node.stdout),
47
+ ...section("stderr", node.stderr)
48
+ ],
49
+ items: []
50
+ };
51
+ }
52
+ function uniqueBy(values, key) {
53
+ const seen = /* @__PURE__ */ new Set();
54
+ return values.filter((value) => {
55
+ const k = key(value);
56
+ if (seen.has(k)) return false;
57
+ seen.add(k);
58
+ return true;
59
+ });
60
+ }
61
+ function mergeCopySections(parts) {
62
+ return {
63
+ facts: uniqueBy(
64
+ parts.flatMap((p) => p.facts ?? []),
65
+ (f) => f.label
66
+ ),
67
+ brief: uniqueBy(
68
+ parts.flatMap((p) => p.brief ?? []),
69
+ (s) => s.title
70
+ ),
71
+ items: uniqueBy(
72
+ parts.flatMap((p) => p.items ?? []),
73
+ (i) => i.label
74
+ )
75
+ };
76
+ }
77
+ function fence(body) {
78
+ const longest = Math.max(0, ...(body.match(/`+/g) ?? []).map((run) => run.length));
79
+ return "`".repeat(Math.max(3, longest + 1));
80
+ }
81
+ function buildBrief(node, sections, facts) {
82
+ const lines = [`# ${node.name}`];
83
+ if (facts.length > 0) lines.push("", ...facts.map((f) => `- **${f.label}:** ${f.value}`));
84
+ for (const s of sections) {
85
+ if (!s.body) continue;
86
+ lines.push("", `## ${s.title}`, "");
87
+ if (s.markdown) {
88
+ lines.push(s.body);
89
+ continue;
90
+ }
91
+ const marker = fence(s.body);
92
+ lines.push(`${marker}${s.lang ?? ""}`, s.body, marker);
93
+ }
94
+ return lines.join("\n");
95
+ }
96
+ function buildNodeBrief(node, adapter) {
97
+ const generic = genericCopySections(node);
98
+ const merged = mergeCopySections([
99
+ { facts: generic.facts, brief: generic.brief.filter((s) => !OUTPUT_TITLES.has(s.title)) },
100
+ adapter,
101
+ { brief: generic.brief.filter((s) => OUTPUT_TITLES.has(s.title)) }
102
+ ]);
103
+ return buildBrief(node, merged.brief, merged.facts);
104
+ }
105
+ function buildNodeJson(node) {
106
+ const { children: _children, ...rest } = node;
107
+ return JSON.stringify(rest, null, 2);
108
+ }
109
+ exports.buildBrief = buildBrief;
110
+ exports.buildNodeBrief = buildNodeBrief;
111
+ exports.buildNodeJson = buildNodeJson;
112
+ exports.genericCopySections = genericCopySections;
113
+ exports.mergeCopySections = mergeCopySections;
114
+ //# sourceMappingURL=copy.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy.cjs","sources":["../../../src/data/test-runner/copy.ts"],"sourcesContent":["// Clipboard payloads for the detail header's \"Copy details\" split button. The\n// primary payload is a Markdown brief: a `# name` heading, `- **Label:** value`\n// facts, then one fenced `## Title` section per piece of evidence. The generic\n// sections here read only common `Test` fields; node adapters contribute the\n// domain sections (a command, a CEL assertion, a recording) and extra menu items\n// through `TestNodeAdapter.copy`. Pure — no React, no clipboard — so every\n// payload is unit-testable as a string.\n\nimport type { StaticIconComponent } from \"../Icon\";\nimport type { Test } from \"./types\";\nimport { formatTestDuration, outcomeFor } from \"./status\";\n\n/** One `- **label:** value` line under the brief's heading. */\nexport type BriefFact = { label: string; value: string };\n\n/**\n * One `## title` block of the brief: fenced (tagged with `lang`) by default, or\n * inserted as-is when `markdown` — for lists and links that must stay live.\n */\nexport type BriefSection = { title: string; lang?: string; markdown?: boolean; body: string };\n\ntype CopyItemBase = { label: string; icon?: StaticIconComponent | string };\n\n/** A copy menu item: the text it copies, or why there is nothing to copy. */\nexport type CopyItem = (CopyItemBase & { value: string }) | (CopyItemBase & { reason: string });\n\nexport type CopySections = {\n facts?: BriefFact[];\n brief?: BriefSection[];\n items?: CopyItem[];\n};\n\n/** Generic sections rendered after every adapter section, so evidence reads before raw output. */\nconst OUTPUT_TITLES = new Set([\"stdout\", \"stderr\"]);\n\nfunction fact(label: string, value: string | undefined): BriefFact[] {\n return value ? [{ label, value }] : [];\n}\n\nfunction section(title: string, body: string | undefined, lang?: string): BriefSection[] {\n if (!body) return [];\n return [lang ? { title, lang, body } : { title, body }];\n}\n\nfunction nodeLocation(node: Test): string | undefined {\n if (!node.file) return undefined;\n return node.line ? `${node.file}:${node.line}` : node.file;\n}\n\nfunction errorBody(node: Test): string {\n const summary = node.failure_detail?.summary;\n const lines = [node.message, summary !== node.message ? summary : undefined];\n return lines.filter(Boolean).join(\"\\n\");\n}\n\nfunction expectationBody(node: Test): string {\n const failure = node.failure_detail;\n if (!failure) return \"\";\n return [\n failure.matcher && `matcher: ${failure.matcher}`,\n failure.expected && `expected: ${failure.expected}`,\n failure.actual && `actual: ${failure.actual}`,\n failure.location && `at: ${failure.location}`,\n ]\n .filter(Boolean)\n .join(\"\\n\");\n}\n\n/** Sections every node gets, read from the common `Test` fields only. */\nexport function genericCopySections(node: Test): Required<CopySections> {\n const duration = node.duration ? formatTestDuration(node.duration) : undefined;\n return {\n facts: [\n ...fact(\"Result\", outcomeFor(node) ?? undefined),\n ...fact(\"Tool\", node.framework),\n ...fact(\"Location\", nodeLocation(node)),\n ...fact(\"Duration\", duration),\n ],\n brief: [\n ...section(\"Error\", errorBody(node)),\n ...section(\"Expectation\", expectationBody(node)),\n ...section(\"Stack\", node.failure_detail?.stack),\n ...section(\"stdout\", node.stdout),\n ...section(\"stderr\", node.stderr),\n ],\n items: [],\n };\n}\n\nfunction uniqueBy<T>(values: T[], key: (value: T) => string): T[] {\n const seen = new Set<string>();\n return values.filter((value) => {\n const k = key(value);\n if (seen.has(k)) return false;\n seen.add(k);\n return true;\n });\n}\n\n/** Concatenates sections in order, keeping the first fact/section/item per label or title. */\nexport function mergeCopySections(parts: CopySections[]): Required<CopySections> {\n return {\n facts: uniqueBy(\n parts.flatMap((p) => p.facts ?? []),\n (f) => f.label,\n ),\n brief: uniqueBy(\n parts.flatMap((p) => p.brief ?? []),\n (s) => s.title,\n ),\n items: uniqueBy(\n parts.flatMap((p) => p.items ?? []),\n (i) => i.label,\n ),\n };\n}\n\n// A fence one backtick longer than any run in the body, so captured output that\n// itself contains ``` cannot close the block early (CommonMark).\nfunction fence(body: string): string {\n const longest = Math.max(0, ...(body.match(/`+/g) ?? []).map((run) => run.length));\n return \"`\".repeat(Math.max(3, longest + 1));\n}\n\n/** The Markdown brief: `# name`, the facts as bullets, then each non-empty section (fenced unless `markdown`). */\nexport function buildBrief(node: Test, sections: BriefSection[], facts: BriefFact[]): string {\n const lines = [`# ${node.name}`];\n if (facts.length > 0) lines.push(\"\", ...facts.map((f) => `- **${f.label}:** ${f.value}`));\n for (const s of sections) {\n if (!s.body) continue;\n lines.push(\"\", `## ${s.title}`, \"\");\n if (s.markdown) {\n lines.push(s.body);\n continue;\n }\n const marker = fence(s.body);\n lines.push(`${marker}${s.lang ?? \"\"}`, s.body, marker);\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * The primary \"Copy details\" payload: generic facts and error/expectation\n * sections, then the adapters' sections, then the captured stdout/stderr.\n */\nexport function buildNodeBrief(node: Test, adapter: CopySections): string {\n const generic = genericCopySections(node);\n const merged = mergeCopySections([\n { facts: generic.facts, brief: generic.brief.filter((s) => !OUTPUT_TITLES.has(s.title)) },\n adapter,\n { brief: generic.brief.filter((s) => OUTPUT_TITLES.has(s.title)) },\n ]);\n return buildBrief(node, merged.brief, merged.facts);\n}\n\n/** \"Copy as JSON\": the node without its children subtree, 2-space indented. */\nexport function buildNodeJson(node: Test): string {\n const { children: _children, ...rest } = node;\n return JSON.stringify(rest, null, 2);\n}\n"],"names":["formatTestDuration","outcomeFor"],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import { StaticIconComponent } from '../Icon.js';
2
+ import { Test } from './types.js';
3
+ /** One `- **label:** value` line under the brief's heading. */
4
+ export type BriefFact = {
5
+ label: string;
6
+ value: string;
7
+ };
8
+ /**
9
+ * One `## title` block of the brief: fenced (tagged with `lang`) by default, or
10
+ * inserted as-is when `markdown` — for lists and links that must stay live.
11
+ */
12
+ export type BriefSection = {
13
+ title: string;
14
+ lang?: string;
15
+ markdown?: boolean;
16
+ body: string;
17
+ };
18
+ type CopyItemBase = {
19
+ label: string;
20
+ icon?: StaticIconComponent | string;
21
+ };
22
+ /** A copy menu item: the text it copies, or why there is nothing to copy. */
23
+ export type CopyItem = (CopyItemBase & {
24
+ value: string;
25
+ }) | (CopyItemBase & {
26
+ reason: string;
27
+ });
28
+ export type CopySections = {
29
+ facts?: BriefFact[];
30
+ brief?: BriefSection[];
31
+ items?: CopyItem[];
32
+ };
33
+ /** Sections every node gets, read from the common `Test` fields only. */
34
+ export declare function genericCopySections(node: Test): Required<CopySections>;
35
+ /** Concatenates sections in order, keeping the first fact/section/item per label or title. */
36
+ export declare function mergeCopySections(parts: CopySections[]): Required<CopySections>;
37
+ /** The Markdown brief: `# name`, the facts as bullets, then each non-empty section (fenced unless `markdown`). */
38
+ export declare function buildBrief(node: Test, sections: BriefSection[], facts: BriefFact[]): string;
39
+ /**
40
+ * The primary "Copy details" payload: generic facts and error/expectation
41
+ * sections, then the adapters' sections, then the captured stdout/stderr.
42
+ */
43
+ export declare function buildNodeBrief(node: Test, adapter: CopySections): string;
44
+ /** "Copy as JSON": the node without its children subtree, 2-space indented. */
45
+ export declare function buildNodeJson(node: Test): string;
46
+ export {};
47
+ //# sourceMappingURL=copy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/copy.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAGpC,+DAA+D;AAC/D,MAAM,MAAM,SAAS,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9F,KAAK,YAAY,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAAA;CAAE,CAAC;AAE3E,6EAA6E;AAC7E,MAAM,MAAM,QAAQ,GAAG,CAAC,YAAY,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,CAAC,YAAY,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEhG,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;CACpB,CAAC;AAsCF,yEAAyE;AACzE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CAAC,YAAY,CAAC,CAkBtE;AAYD,8FAA8F;AAC9F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,QAAQ,CAAC,YAAY,CAAC,CAe/E;AASD,kHAAkH;AAClH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,CAc3F;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,CAQxE;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAGhD"}
@@ -0,0 +1,114 @@
1
+ import { formatTestDuration, outcomeFor } from "./status.js";
2
+ const OUTPUT_TITLES = /* @__PURE__ */ new Set(["stdout", "stderr"]);
3
+ function fact(label, value) {
4
+ return value ? [{ label, value }] : [];
5
+ }
6
+ function section(title, body, lang) {
7
+ if (!body) return [];
8
+ return [lang ? { title, lang, body } : { title, body }];
9
+ }
10
+ function nodeLocation(node) {
11
+ if (!node.file) return void 0;
12
+ return node.line ? `${node.file}:${node.line}` : node.file;
13
+ }
14
+ function errorBody(node) {
15
+ var _a;
16
+ const summary = (_a = node.failure_detail) == null ? void 0 : _a.summary;
17
+ const lines = [node.message, summary !== node.message ? summary : void 0];
18
+ return lines.filter(Boolean).join("\n");
19
+ }
20
+ function expectationBody(node) {
21
+ const failure = node.failure_detail;
22
+ if (!failure) return "";
23
+ return [
24
+ failure.matcher && `matcher: ${failure.matcher}`,
25
+ failure.expected && `expected: ${failure.expected}`,
26
+ failure.actual && `actual: ${failure.actual}`,
27
+ failure.location && `at: ${failure.location}`
28
+ ].filter(Boolean).join("\n");
29
+ }
30
+ function genericCopySections(node) {
31
+ var _a;
32
+ const duration = node.duration ? formatTestDuration(node.duration) : void 0;
33
+ return {
34
+ facts: [
35
+ ...fact("Result", outcomeFor(node) ?? void 0),
36
+ ...fact("Tool", node.framework),
37
+ ...fact("Location", nodeLocation(node)),
38
+ ...fact("Duration", duration)
39
+ ],
40
+ brief: [
41
+ ...section("Error", errorBody(node)),
42
+ ...section("Expectation", expectationBody(node)),
43
+ ...section("Stack", (_a = node.failure_detail) == null ? void 0 : _a.stack),
44
+ ...section("stdout", node.stdout),
45
+ ...section("stderr", node.stderr)
46
+ ],
47
+ items: []
48
+ };
49
+ }
50
+ function uniqueBy(values, key) {
51
+ const seen = /* @__PURE__ */ new Set();
52
+ return values.filter((value) => {
53
+ const k = key(value);
54
+ if (seen.has(k)) return false;
55
+ seen.add(k);
56
+ return true;
57
+ });
58
+ }
59
+ function mergeCopySections(parts) {
60
+ return {
61
+ facts: uniqueBy(
62
+ parts.flatMap((p) => p.facts ?? []),
63
+ (f) => f.label
64
+ ),
65
+ brief: uniqueBy(
66
+ parts.flatMap((p) => p.brief ?? []),
67
+ (s) => s.title
68
+ ),
69
+ items: uniqueBy(
70
+ parts.flatMap((p) => p.items ?? []),
71
+ (i) => i.label
72
+ )
73
+ };
74
+ }
75
+ function fence(body) {
76
+ const longest = Math.max(0, ...(body.match(/`+/g) ?? []).map((run) => run.length));
77
+ return "`".repeat(Math.max(3, longest + 1));
78
+ }
79
+ function buildBrief(node, sections, facts) {
80
+ const lines = [`# ${node.name}`];
81
+ if (facts.length > 0) lines.push("", ...facts.map((f) => `- **${f.label}:** ${f.value}`));
82
+ for (const s of sections) {
83
+ if (!s.body) continue;
84
+ lines.push("", `## ${s.title}`, "");
85
+ if (s.markdown) {
86
+ lines.push(s.body);
87
+ continue;
88
+ }
89
+ const marker = fence(s.body);
90
+ lines.push(`${marker}${s.lang ?? ""}`, s.body, marker);
91
+ }
92
+ return lines.join("\n");
93
+ }
94
+ function buildNodeBrief(node, adapter) {
95
+ const generic = genericCopySections(node);
96
+ const merged = mergeCopySections([
97
+ { facts: generic.facts, brief: generic.brief.filter((s) => !OUTPUT_TITLES.has(s.title)) },
98
+ adapter,
99
+ { brief: generic.brief.filter((s) => OUTPUT_TITLES.has(s.title)) }
100
+ ]);
101
+ return buildBrief(node, merged.brief, merged.facts);
102
+ }
103
+ function buildNodeJson(node) {
104
+ const { children: _children, ...rest } = node;
105
+ return JSON.stringify(rest, null, 2);
106
+ }
107
+ export {
108
+ buildBrief,
109
+ buildNodeBrief,
110
+ buildNodeJson,
111
+ genericCopySections,
112
+ mergeCopySections
113
+ };
114
+ //# sourceMappingURL=copy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy.js","sources":["../../../src/data/test-runner/copy.ts"],"sourcesContent":["// Clipboard payloads for the detail header's \"Copy details\" split button. The\n// primary payload is a Markdown brief: a `# name` heading, `- **Label:** value`\n// facts, then one fenced `## Title` section per piece of evidence. The generic\n// sections here read only common `Test` fields; node adapters contribute the\n// domain sections (a command, a CEL assertion, a recording) and extra menu items\n// through `TestNodeAdapter.copy`. Pure — no React, no clipboard — so every\n// payload is unit-testable as a string.\n\nimport type { StaticIconComponent } from \"../Icon\";\nimport type { Test } from \"./types\";\nimport { formatTestDuration, outcomeFor } from \"./status\";\n\n/** One `- **label:** value` line under the brief's heading. */\nexport type BriefFact = { label: string; value: string };\n\n/**\n * One `## title` block of the brief: fenced (tagged with `lang`) by default, or\n * inserted as-is when `markdown` — for lists and links that must stay live.\n */\nexport type BriefSection = { title: string; lang?: string; markdown?: boolean; body: string };\n\ntype CopyItemBase = { label: string; icon?: StaticIconComponent | string };\n\n/** A copy menu item: the text it copies, or why there is nothing to copy. */\nexport type CopyItem = (CopyItemBase & { value: string }) | (CopyItemBase & { reason: string });\n\nexport type CopySections = {\n facts?: BriefFact[];\n brief?: BriefSection[];\n items?: CopyItem[];\n};\n\n/** Generic sections rendered after every adapter section, so evidence reads before raw output. */\nconst OUTPUT_TITLES = new Set([\"stdout\", \"stderr\"]);\n\nfunction fact(label: string, value: string | undefined): BriefFact[] {\n return value ? [{ label, value }] : [];\n}\n\nfunction section(title: string, body: string | undefined, lang?: string): BriefSection[] {\n if (!body) return [];\n return [lang ? { title, lang, body } : { title, body }];\n}\n\nfunction nodeLocation(node: Test): string | undefined {\n if (!node.file) return undefined;\n return node.line ? `${node.file}:${node.line}` : node.file;\n}\n\nfunction errorBody(node: Test): string {\n const summary = node.failure_detail?.summary;\n const lines = [node.message, summary !== node.message ? summary : undefined];\n return lines.filter(Boolean).join(\"\\n\");\n}\n\nfunction expectationBody(node: Test): string {\n const failure = node.failure_detail;\n if (!failure) return \"\";\n return [\n failure.matcher && `matcher: ${failure.matcher}`,\n failure.expected && `expected: ${failure.expected}`,\n failure.actual && `actual: ${failure.actual}`,\n failure.location && `at: ${failure.location}`,\n ]\n .filter(Boolean)\n .join(\"\\n\");\n}\n\n/** Sections every node gets, read from the common `Test` fields only. */\nexport function genericCopySections(node: Test): Required<CopySections> {\n const duration = node.duration ? formatTestDuration(node.duration) : undefined;\n return {\n facts: [\n ...fact(\"Result\", outcomeFor(node) ?? undefined),\n ...fact(\"Tool\", node.framework),\n ...fact(\"Location\", nodeLocation(node)),\n ...fact(\"Duration\", duration),\n ],\n brief: [\n ...section(\"Error\", errorBody(node)),\n ...section(\"Expectation\", expectationBody(node)),\n ...section(\"Stack\", node.failure_detail?.stack),\n ...section(\"stdout\", node.stdout),\n ...section(\"stderr\", node.stderr),\n ],\n items: [],\n };\n}\n\nfunction uniqueBy<T>(values: T[], key: (value: T) => string): T[] {\n const seen = new Set<string>();\n return values.filter((value) => {\n const k = key(value);\n if (seen.has(k)) return false;\n seen.add(k);\n return true;\n });\n}\n\n/** Concatenates sections in order, keeping the first fact/section/item per label or title. */\nexport function mergeCopySections(parts: CopySections[]): Required<CopySections> {\n return {\n facts: uniqueBy(\n parts.flatMap((p) => p.facts ?? []),\n (f) => f.label,\n ),\n brief: uniqueBy(\n parts.flatMap((p) => p.brief ?? []),\n (s) => s.title,\n ),\n items: uniqueBy(\n parts.flatMap((p) => p.items ?? []),\n (i) => i.label,\n ),\n };\n}\n\n// A fence one backtick longer than any run in the body, so captured output that\n// itself contains ``` cannot close the block early (CommonMark).\nfunction fence(body: string): string {\n const longest = Math.max(0, ...(body.match(/`+/g) ?? []).map((run) => run.length));\n return \"`\".repeat(Math.max(3, longest + 1));\n}\n\n/** The Markdown brief: `# name`, the facts as bullets, then each non-empty section (fenced unless `markdown`). */\nexport function buildBrief(node: Test, sections: BriefSection[], facts: BriefFact[]): string {\n const lines = [`# ${node.name}`];\n if (facts.length > 0) lines.push(\"\", ...facts.map((f) => `- **${f.label}:** ${f.value}`));\n for (const s of sections) {\n if (!s.body) continue;\n lines.push(\"\", `## ${s.title}`, \"\");\n if (s.markdown) {\n lines.push(s.body);\n continue;\n }\n const marker = fence(s.body);\n lines.push(`${marker}${s.lang ?? \"\"}`, s.body, marker);\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * The primary \"Copy details\" payload: generic facts and error/expectation\n * sections, then the adapters' sections, then the captured stdout/stderr.\n */\nexport function buildNodeBrief(node: Test, adapter: CopySections): string {\n const generic = genericCopySections(node);\n const merged = mergeCopySections([\n { facts: generic.facts, brief: generic.brief.filter((s) => !OUTPUT_TITLES.has(s.title)) },\n adapter,\n { brief: generic.brief.filter((s) => OUTPUT_TITLES.has(s.title)) },\n ]);\n return buildBrief(node, merged.brief, merged.facts);\n}\n\n/** \"Copy as JSON\": the node without its children subtree, 2-space indented. */\nexport function buildNodeJson(node: Test): string {\n const { children: _children, ...rest } = node;\n return JSON.stringify(rest, null, 2);\n}\n"],"names":[],"mappings":"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"}
@@ -3,12 +3,15 @@ export { TestTree } from './TestTree.js';
3
3
  export { TestTreeNode } from './TestTreeNode.js';
4
4
  export { TestDetailPanel } from './TestDetailPanel.js';
5
5
  export { TestFailureDetail, TestOutput, TestAttempts, } from './TestFailureDetail.js';
6
+ export { Expectation, type ExpectationProps } from './Expectation.js';
6
7
  export { TestRunSummary, type TestRunSummaryProps } from './TestRunSummary.js';
7
8
  export { TestFilterBar, type TestFilterBarProps } from './TestFilterBar.js';
8
9
  export { TestRunnerProvider, useTestRunner, type TestRunnerContext, } from './context.js';
9
10
  export { TestNodeAdapterRegistry, createTestRunnerRegistry, type TestNodeAdapter, type AdapterContext, type DetailTab, } from './adapter.js';
10
- export { type StatusCounts, type TestStatus, sum, sumNonTaskTests, aggregateStatusCounts, STATUS_LABELS, hasFailed, hasPending, testStatus, totalDuration, statusIconFor, statusToneFor, formatTestDuration, formatCount, humanizeName, collectFrameworks, collapseSingleChildChains, filterTests, } from './status.js';
11
- export { frameworkIcon } from './frameworkIcon.js';
11
+ export { genericCopySections, mergeCopySections, buildBrief, buildNodeBrief, buildNodeJson, type BriefFact, type BriefSection, type CopyItem, type CopySections, } from './copy.js';
12
+ export { type StatusCounts, type TestStatus, sum, sumNonTaskTests, aggregateStatusCounts, STATUS_LABELS, hasFailed, hasPending, testStatus, totalDuration, outcomeFor, type TestOutcome, statusToneFor, formatTestDuration, formatCount, humanizeName, collectFrameworks, collapseSingleChildChains, filterTests, } from './status.js';
13
+ export { TEST_OUTCOMES, LINT_SEVERITIES, TEST_TOOLS, toolMark, type ResultMark, type LintSeverity, type ToolKind, type ToolMark, } from './marks.js';
14
+ export { OutcomeIcon, LintSeverityIcon, ToolIcon } from './MarkIcons.js';
12
15
  export { slugify, annotateRoutePaths, findNodeByRoutePath } from './routePath.js';
13
16
  export { type FilterMode, type FilterState, type TestFilters, emptyTestFilters, decodeFilterState, encodeFilterState, cycleFilterState, matchesFilterState, filterStateToRecord, recordToFilterState, } from './filterState.js';
14
17
  export type { Test, TestSummary, TestAttempt, FailureDetail, FailureKind, GoTestContext, GinkgoContext, FixtureContext, TaskContext, RunMeta, Snapshot, SnapshotGit, SnapshotStatus, } from './types.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,YAAY,GACb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAEzE,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,KAAK,iBAAiB,GACvB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,SAAS,GACf,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,GAAG,EACH,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,SAAS,EACT,UAAU,EACV,UAAU,EACV,aAAa,EACb,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,yBAAyB,EACzB,WAAW,GACZ,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAE/E,OAAO,EACL,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,IAAI,EACJ,WAAW,EACX,WAAW,EACX,aAAa,EACb,WAAW,EACX,aAAa,EACb,aAAa,EACb,cAAc,EACd,WAAW,EACX,OAAO,EACP,QAAQ,EACR,WAAW,EACX,cAAc,GACf,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,YAAY,GACb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAEzE,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,KAAK,iBAAiB,GACvB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,SAAS,GACf,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,aAAa,EACb,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,YAAY,GAClB,MAAM,QAAQ,CAAC;AAEhB,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,GAAG,EACH,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,SAAS,EACT,UAAU,EACV,UAAU,EACV,aAAa,EACb,UAAU,EACV,KAAK,WAAW,EAChB,aAAa,EACb,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,yBAAyB,EACzB,WAAW,GACZ,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,aAAa,EACb,eAAe,EACf,UAAU,EACV,QAAQ,EACR,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,QAAQ,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEtE,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAE/E,OAAO,EACL,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,IAAI,EACJ,WAAW,EACX,WAAW,EACX,aAAa,EACb,WAAW,EACX,aAAa,EACb,aAAa,EACb,cAAc,EACd,WAAW,EACX,OAAO,EACP,QAAQ,EACR,WAAW,EACX,cAAc,GACf,MAAM,SAAS,CAAC"}