@corbet-labs/ccht 0.2.2 → 0.2.4

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 (397) hide show
  1. package/LICENSE +307 -0
  2. package/LICENSE.md +30 -0
  3. package/LICENSES/GPL-3.0-only.txt +232 -0
  4. package/LICENSES/LGPL-3.0-linking-exception.txt +16 -0
  5. package/LICENSES/LGPL-3.0-only WITH LGPL-3.0-linking-exception.txt +16 -0
  6. package/LICENSES/LGPL-3.0-only.txt +304 -0
  7. package/LICENSES/dependencies/agent-client-protocol-2.1.0/LICENSE +191 -0
  8. package/LICENSES/dependencies/agent-client-protocol-derive-2.1.0/LICENSE +191 -0
  9. package/LICENSES/dependencies/agent-client-protocol-schema-1.7.0/LICENSE +190 -0
  10. package/LICENSES/dependencies/android_system_properties-0.1.6/LICENSE-APACHE +13 -0
  11. package/LICENSES/dependencies/android_system_properties-0.1.6/LICENSE-MIT +20 -0
  12. package/LICENSES/dependencies/anyhow-1.0.104/LICENSE-APACHE +176 -0
  13. package/LICENSES/dependencies/anyhow-1.0.104/LICENSE-MIT +23 -0
  14. package/LICENSES/dependencies/async-channel-2.5.0/LICENSE-APACHE +201 -0
  15. package/LICENSES/dependencies/async-channel-2.5.0/LICENSE-MIT +23 -0
  16. package/LICENSES/dependencies/async-io-2.6.0/LICENSE-APACHE +201 -0
  17. package/LICENSES/dependencies/async-io-2.6.0/LICENSE-MIT +23 -0
  18. package/LICENSES/dependencies/async-lock-3.4.2/LICENSE-APACHE +201 -0
  19. package/LICENSES/dependencies/async-lock-3.4.2/LICENSE-MIT +23 -0
  20. package/LICENSES/dependencies/async-process-2.5.0/LICENSE-APACHE +201 -0
  21. package/LICENSES/dependencies/async-process-2.5.0/LICENSE-MIT +23 -0
  22. package/LICENSES/dependencies/async-signal-0.2.14/LICENSE-APACHE +201 -0
  23. package/LICENSES/dependencies/async-signal-0.2.14/LICENSE-MIT +23 -0
  24. package/LICENSES/dependencies/async-task-4.7.1/LICENSE-APACHE +201 -0
  25. package/LICENSES/dependencies/async-task-4.7.1/LICENSE-MIT +23 -0
  26. package/LICENSES/dependencies/atomic-waker-1.1.2/LICENSE-APACHE +201 -0
  27. package/LICENSES/dependencies/atomic-waker-1.1.2/LICENSE-MIT +23 -0
  28. package/LICENSES/dependencies/atomic-waker-1.1.2/LICENSE-THIRD-PARTY +45 -0
  29. package/LICENSES/dependencies/autocfg-1.5.1/LICENSE-APACHE +201 -0
  30. package/LICENSES/dependencies/autocfg-1.5.1/LICENSE-MIT +25 -0
  31. package/LICENSES/dependencies/base64-0.22.1/LICENSE-APACHE +201 -0
  32. package/LICENSES/dependencies/base64-0.22.1/LICENSE-MIT +21 -0
  33. package/LICENSES/dependencies/base64-0.23.1/LICENSE-APACHE +201 -0
  34. package/LICENSES/dependencies/base64-0.23.1/LICENSE-MIT +21 -0
  35. package/LICENSES/dependencies/bitflags-1.3.2/LICENSE-APACHE +201 -0
  36. package/LICENSES/dependencies/bitflags-1.3.2/LICENSE-MIT +25 -0
  37. package/LICENSES/dependencies/bitflags-2.13.2/LICENSE-APACHE +201 -0
  38. package/LICENSES/dependencies/bitflags-2.13.2/LICENSE-MIT +25 -0
  39. package/LICENSES/dependencies/blocking-1.7.0/LICENSE-APACHE +201 -0
  40. package/LICENSES/dependencies/blocking-1.7.0/LICENSE-MIT +23 -0
  41. package/LICENSES/dependencies/bs58-0.5.1/LICENSE-APACHE +201 -0
  42. package/LICENSES/dependencies/bs58-0.5.1/LICENSE-MIT +20 -0
  43. package/LICENSES/dependencies/bumpalo-3.20.3/LICENSE-APACHE +201 -0
  44. package/LICENSES/dependencies/bumpalo-3.20.3/LICENSE-MIT +25 -0
  45. package/LICENSES/dependencies/bytes-1.12.1/LICENSE +25 -0
  46. package/LICENSES/dependencies/cc-1.4.5/LICENSE-APACHE +201 -0
  47. package/LICENSES/dependencies/cc-1.4.5/LICENSE-MIT +25 -0
  48. package/LICENSES/dependencies/cfg-if-1.0.4/LICENSE-APACHE +201 -0
  49. package/LICENSES/dependencies/cfg-if-1.0.4/LICENSE-MIT +25 -0
  50. package/LICENSES/dependencies/chrono-0.4.45/LICENSE.txt +240 -0
  51. package/LICENSES/dependencies/concurrent-queue-2.5.0/LICENSE-APACHE +201 -0
  52. package/LICENSES/dependencies/concurrent-queue-2.5.0/LICENSE-MIT +23 -0
  53. package/LICENSES/dependencies/convert_case-0.10.0/LICENSE +21 -0
  54. package/LICENSES/dependencies/core-foundation-sys-0.8.7/LICENSE-APACHE +201 -0
  55. package/LICENSES/dependencies/core-foundation-sys-0.8.7/LICENSE-MIT +25 -0
  56. package/LICENSES/dependencies/crossbeam-deque-0.8.8/LICENSE-APACHE +201 -0
  57. package/LICENSES/dependencies/crossbeam-deque-0.8.8/LICENSE-MIT +27 -0
  58. package/LICENSES/dependencies/crossbeam-epoch-0.9.21/LICENSE-APACHE +201 -0
  59. package/LICENSES/dependencies/crossbeam-epoch-0.9.21/LICENSE-MIT +27 -0
  60. package/LICENSES/dependencies/crossbeam-utils-0.8.23/LICENSE-APACHE +201 -0
  61. package/LICENSES/dependencies/crossbeam-utils-0.8.23/LICENSE-MIT +27 -0
  62. package/LICENSES/dependencies/darling-0.24.1/LICENSE +21 -0
  63. package/LICENSES/dependencies/darling_core-0.24.1/LICENSE +21 -0
  64. package/LICENSES/dependencies/darling_macro-0.24.1/LICENSE +21 -0
  65. package/LICENSES/dependencies/defmt-1.1.1/LICENSE-APACHE +201 -0
  66. package/LICENSES/dependencies/defmt-1.1.1/LICENSE-MIT +25 -0
  67. package/LICENSES/dependencies/defmt-macros-1.1.1/LICENSE-APACHE +201 -0
  68. package/LICENSES/dependencies/defmt-macros-1.1.1/LICENSE-MIT +25 -0
  69. package/LICENSES/dependencies/defmt-parser-1.0.0/LICENSE-APACHE +201 -0
  70. package/LICENSES/dependencies/defmt-parser-1.0.0/LICENSE-MIT +25 -0
  71. package/LICENSES/dependencies/deranged-0.5.8/LICENSE-Apache +202 -0
  72. package/LICENSES/dependencies/deranged-0.5.8/LICENSE-MIT +19 -0
  73. package/LICENSES/dependencies/derive_more-2.1.1/LICENSE +21 -0
  74. package/LICENSES/dependencies/derive_more-impl-2.1.1/LICENSE +21 -0
  75. package/LICENSES/dependencies/dyn-clone-1.0.20/LICENSE-APACHE +176 -0
  76. package/LICENSES/dependencies/dyn-clone-1.0.20/LICENSE-MIT +23 -0
  77. package/LICENSES/dependencies/either-1.18.0/LICENSE-APACHE +201 -0
  78. package/LICENSES/dependencies/either-1.18.0/LICENSE-MIT +25 -0
  79. package/LICENSES/dependencies/equivalent-1.0.2/LICENSE-APACHE +201 -0
  80. package/LICENSES/dependencies/equivalent-1.0.2/LICENSE-MIT +25 -0
  81. package/LICENSES/dependencies/errno-0.3.14/LICENSE-APACHE +201 -0
  82. package/LICENSES/dependencies/errno-0.3.14/LICENSE-MIT +25 -0
  83. package/LICENSES/dependencies/event-listener-5.4.2/LICENSE-APACHE +201 -0
  84. package/LICENSES/dependencies/event-listener-5.4.2/LICENSE-MIT +23 -0
  85. package/LICENSES/dependencies/event-listener-strategy-0.5.4/LICENSE-APACHE +201 -0
  86. package/LICENSES/dependencies/event-listener-strategy-0.5.4/LICENSE-MIT +23 -0
  87. package/LICENSES/dependencies/fallible-iterator-0.3.0/LICENSE-APACHE +202 -0
  88. package/LICENSES/dependencies/fallible-iterator-0.3.0/LICENSE-MIT +19 -0
  89. package/LICENSES/dependencies/fastrand-2.5.0/LICENSE-APACHE +201 -0
  90. package/LICENSES/dependencies/fastrand-2.5.0/LICENSE-MIT +23 -0
  91. package/LICENSES/dependencies/find-msvc-tools-0.1.12/LICENSE-APACHE +201 -0
  92. package/LICENSES/dependencies/find-msvc-tools-0.1.12/LICENSE-MIT +25 -0
  93. package/LICENSES/dependencies/fixedbitset-0.5.7/LICENSE-APACHE +201 -0
  94. package/LICENSES/dependencies/fixedbitset-0.5.7/LICENSE-MIT +25 -0
  95. package/LICENSES/dependencies/foldhash-0.2.0/LICENSE +19 -0
  96. package/LICENSES/dependencies/futures-0.3.34/LICENSE-APACHE +202 -0
  97. package/LICENSES/dependencies/futures-0.3.34/LICENSE-MIT +26 -0
  98. package/LICENSES/dependencies/futures-channel-0.3.34/LICENSE-APACHE +202 -0
  99. package/LICENSES/dependencies/futures-channel-0.3.34/LICENSE-MIT +26 -0
  100. package/LICENSES/dependencies/futures-concurrency-7.7.1/LICENSE-APACHE +190 -0
  101. package/LICENSES/dependencies/futures-concurrency-7.7.1/LICENSE-MIT +21 -0
  102. package/LICENSES/dependencies/futures-core-0.3.34/LICENSE-APACHE +202 -0
  103. package/LICENSES/dependencies/futures-core-0.3.34/LICENSE-MIT +26 -0
  104. package/LICENSES/dependencies/futures-executor-0.3.34/LICENSE-APACHE +202 -0
  105. package/LICENSES/dependencies/futures-executor-0.3.34/LICENSE-MIT +26 -0
  106. package/LICENSES/dependencies/futures-io-0.3.34/LICENSE-APACHE +202 -0
  107. package/LICENSES/dependencies/futures-io-0.3.34/LICENSE-MIT +26 -0
  108. package/LICENSES/dependencies/futures-lite-2.6.1/LICENSE-APACHE +201 -0
  109. package/LICENSES/dependencies/futures-lite-2.6.1/LICENSE-MIT +23 -0
  110. package/LICENSES/dependencies/futures-lite-2.6.1/LICENSE-THIRD-PARTY +45 -0
  111. package/LICENSES/dependencies/futures-macro-0.3.34/LICENSE-APACHE +202 -0
  112. package/LICENSES/dependencies/futures-macro-0.3.34/LICENSE-MIT +26 -0
  113. package/LICENSES/dependencies/futures-sink-0.3.34/LICENSE-APACHE +202 -0
  114. package/LICENSES/dependencies/futures-sink-0.3.34/LICENSE-MIT +26 -0
  115. package/LICENSES/dependencies/futures-task-0.3.34/LICENSE-APACHE +202 -0
  116. package/LICENSES/dependencies/futures-task-0.3.34/LICENSE-MIT +26 -0
  117. package/LICENSES/dependencies/futures-util-0.3.34/LICENSE-APACHE +202 -0
  118. package/LICENSES/dependencies/futures-util-0.3.34/LICENSE-MIT +26 -0
  119. package/LICENSES/dependencies/getrandom-0.4.3/LICENSE-APACHE +201 -0
  120. package/LICENSES/dependencies/getrandom-0.4.3/LICENSE-MIT +26 -0
  121. package/LICENSES/dependencies/gimli-0.32.3/LICENSE-APACHE +201 -0
  122. package/LICENSES/dependencies/gimli-0.32.3/LICENSE-MIT +25 -0
  123. package/LICENSES/dependencies/hashbrown-0.12.3/LICENSE-APACHE +201 -0
  124. package/LICENSES/dependencies/hashbrown-0.12.3/LICENSE-MIT +25 -0
  125. package/LICENSES/dependencies/hashbrown-0.16.1/LICENSE-APACHE +201 -0
  126. package/LICENSES/dependencies/hashbrown-0.16.1/LICENSE-MIT +25 -0
  127. package/LICENSES/dependencies/hashbrown-0.17.1/LICENSE-APACHE +201 -0
  128. package/LICENSES/dependencies/hashbrown-0.17.1/LICENSE-MIT +25 -0
  129. package/LICENSES/dependencies/heck-0.5.0/LICENSE-APACHE +201 -0
  130. package/LICENSES/dependencies/heck-0.5.0/LICENSE-MIT +25 -0
  131. package/LICENSES/dependencies/hermit-abi-0.5.3/LICENSE-APACHE +201 -0
  132. package/LICENSES/dependencies/hermit-abi-0.5.3/LICENSE-MIT +23 -0
  133. package/LICENSES/dependencies/hex-0.4.3/LICENSE-APACHE +202 -0
  134. package/LICENSES/dependencies/hex-0.4.3/LICENSE-MIT +20 -0
  135. package/LICENSES/dependencies/iana-time-zone-0.1.65/LICENSE-APACHE +201 -0
  136. package/LICENSES/dependencies/iana-time-zone-0.1.65/LICENSE-MIT +25 -0
  137. package/LICENSES/dependencies/iana-time-zone-haiku-0.1.2/LICENSE-APACHE +201 -0
  138. package/LICENSES/dependencies/iana-time-zone-haiku-0.1.2/LICENSE-MIT +25 -0
  139. package/LICENSES/dependencies/id-arena-2.3.0/LICENSE-APACHE +201 -0
  140. package/LICENSES/dependencies/id-arena-2.3.0/LICENSE-MIT +25 -0
  141. package/LICENSES/dependencies/ident_case-1.0.1/LICENSE +19 -0
  142. package/LICENSES/dependencies/indexmap-1.9.3/LICENSE-APACHE +201 -0
  143. package/LICENSES/dependencies/indexmap-1.9.3/LICENSE-MIT +25 -0
  144. package/LICENSES/dependencies/indexmap-2.14.2/LICENSE-APACHE +201 -0
  145. package/LICENSES/dependencies/indexmap-2.14.2/LICENSE-MIT +25 -0
  146. package/LICENSES/dependencies/itoa-1.0.18/LICENSE-APACHE +176 -0
  147. package/LICENSES/dependencies/itoa-1.0.18/LICENSE-MIT +23 -0
  148. package/LICENSES/dependencies/jiff-0.2.35/COPYING +3 -0
  149. package/LICENSES/dependencies/jiff-0.2.35/LICENSE-MIT +21 -0
  150. package/LICENSES/dependencies/jiff-0.2.35/UNLICENSE +24 -0
  151. package/LICENSES/dependencies/jiff-core-0.1.0/COPYING +3 -0
  152. package/LICENSES/dependencies/jiff-core-0.1.0/LICENSE-MIT +21 -0
  153. package/LICENSES/dependencies/jiff-core-0.1.0/UNLICENSE +24 -0
  154. package/LICENSES/dependencies/jiff-static-0.2.35/COPYING +3 -0
  155. package/LICENSES/dependencies/jiff-static-0.2.35/LICENSE-MIT +21 -0
  156. package/LICENSES/dependencies/jiff-static-0.2.35/UNLICENSE +24 -0
  157. package/LICENSES/dependencies/jiff-tzdb-0.1.8/COPYING +3 -0
  158. package/LICENSES/dependencies/jiff-tzdb-0.1.8/LICENSE-MIT +21 -0
  159. package/LICENSES/dependencies/jiff-tzdb-0.1.8/UNLICENSE +24 -0
  160. package/LICENSES/dependencies/jiff-tzdb-platform-0.1.3/COPYING +3 -0
  161. package/LICENSES/dependencies/jiff-tzdb-platform-0.1.3/LICENSE-MIT +21 -0
  162. package/LICENSES/dependencies/jiff-tzdb-platform-0.1.3/UNLICENSE +24 -0
  163. package/LICENSES/dependencies/js-sys-0.3.105/LICENSE-APACHE +201 -0
  164. package/LICENSES/dependencies/js-sys-0.3.105/LICENSE-MIT +25 -0
  165. package/LICENSES/dependencies/leb128-0.2.7/LICENSE-APACHE +201 -0
  166. package/LICENSES/dependencies/leb128-0.2.7/LICENSE-MIT +25 -0
  167. package/LICENSES/dependencies/leb128fmt-0.1.0/LICENSE-APACHE +201 -0
  168. package/LICENSES/dependencies/leb128fmt-0.1.0/LICENSE-MIT +23 -0
  169. package/LICENSES/dependencies/libc-0.2.189/LICENSE-APACHE +176 -0
  170. package/LICENSES/dependencies/libc-0.2.189/LICENSE-MIT +25 -0
  171. package/LICENSES/dependencies/linux-raw-sys-0.12.1/COPYRIGHT +29 -0
  172. package/LICENSES/dependencies/linux-raw-sys-0.12.1/LICENSE-APACHE +201 -0
  173. package/LICENSES/dependencies/linux-raw-sys-0.12.1/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
  174. package/LICENSES/dependencies/linux-raw-sys-0.12.1/LICENSE-MIT +23 -0
  175. package/LICENSES/dependencies/log-0.4.34/LICENSE-APACHE +201 -0
  176. package/LICENSES/dependencies/log-0.4.34/LICENSE-MIT +25 -0
  177. package/LICENSES/dependencies/memchr-2.8.3/COPYING +3 -0
  178. package/LICENSES/dependencies/memchr-2.8.3/LICENSE-MIT +21 -0
  179. package/LICENSES/dependencies/memchr-2.8.3/UNLICENSE +24 -0
  180. package/LICENSES/dependencies/mio-1.2.3/LICENSE +19 -0
  181. package/LICENSES/dependencies/num-conv-0.2.2/LICENSE-Apache +177 -0
  182. package/LICENSES/dependencies/num-conv-0.2.2/LICENSE-MIT +19 -0
  183. package/LICENSES/dependencies/num-traits-0.2.19/LICENSE-APACHE +201 -0
  184. package/LICENSES/dependencies/num-traits-0.2.19/LICENSE-MIT +25 -0
  185. package/LICENSES/dependencies/once_cell-1.21.4/LICENSE-APACHE +201 -0
  186. package/LICENSES/dependencies/once_cell-1.21.4/LICENSE-MIT +23 -0
  187. package/LICENSES/dependencies/parking-2.2.1/LICENSE-APACHE +201 -0
  188. package/LICENSES/dependencies/parking-2.2.1/LICENSE-MIT +23 -0
  189. package/LICENSES/dependencies/parking-2.2.1/LICENSE-THIRD-PARTY +9 -0
  190. package/LICENSES/dependencies/pin-project-1.1.13/LICENSE-APACHE +177 -0
  191. package/LICENSES/dependencies/pin-project-1.1.13/LICENSE-MIT +23 -0
  192. package/LICENSES/dependencies/pin-project-internal-1.1.13/LICENSE-APACHE +177 -0
  193. package/LICENSES/dependencies/pin-project-internal-1.1.13/LICENSE-MIT +23 -0
  194. package/LICENSES/dependencies/pin-project-lite-0.2.17/LICENSE-APACHE +177 -0
  195. package/LICENSES/dependencies/pin-project-lite-0.2.17/LICENSE-MIT +23 -0
  196. package/LICENSES/dependencies/piper-0.2.5/LICENSE-APACHE +201 -0
  197. package/LICENSES/dependencies/piper-0.2.5/LICENSE-MIT +23 -0
  198. package/LICENSES/dependencies/polling-3.11.0/LICENSE-APACHE +201 -0
  199. package/LICENSES/dependencies/polling-3.11.0/LICENSE-MIT +23 -0
  200. package/LICENSES/dependencies/portable-atomic-1.15.0/LICENSE-APACHE +177 -0
  201. package/LICENSES/dependencies/portable-atomic-1.15.0/LICENSE-MIT +23 -0
  202. package/LICENSES/dependencies/portable-atomic-util-0.2.8/LICENSE-APACHE +177 -0
  203. package/LICENSES/dependencies/portable-atomic-util-0.2.8/LICENSE-MIT +23 -0
  204. package/LICENSES/dependencies/powerfmt-0.2.0/LICENSE-Apache +202 -0
  205. package/LICENSES/dependencies/powerfmt-0.2.0/LICENSE-MIT +19 -0
  206. package/LICENSES/dependencies/proc-macro2-1.0.107/LICENSE-APACHE +176 -0
  207. package/LICENSES/dependencies/proc-macro2-1.0.107/LICENSE-MIT +23 -0
  208. package/LICENSES/dependencies/quote-1.0.47/LICENSE-APACHE +176 -0
  209. package/LICENSES/dependencies/quote-1.0.47/LICENSE-MIT +23 -0
  210. package/LICENSES/dependencies/r-efi-6.0.0/AUTHORS +75 -0
  211. package/LICENSES/dependencies/rayon-1.12.0/LICENSE-APACHE +201 -0
  212. package/LICENSES/dependencies/rayon-1.12.0/LICENSE-MIT +25 -0
  213. package/LICENSES/dependencies/rayon-core-1.13.0/LICENSE-APACHE +201 -0
  214. package/LICENSES/dependencies/rayon-core-1.13.0/LICENSE-MIT +25 -0
  215. package/LICENSES/dependencies/ref-cast-1.0.27/LICENSE-APACHE +176 -0
  216. package/LICENSES/dependencies/ref-cast-1.0.27/LICENSE-MIT +23 -0
  217. package/LICENSES/dependencies/ref-cast-impl-1.0.27/LICENSE-APACHE +176 -0
  218. package/LICENSES/dependencies/ref-cast-impl-1.0.27/LICENSE-MIT +23 -0
  219. package/LICENSES/dependencies/rustc-demangle-0.1.28/LICENSE-APACHE +201 -0
  220. package/LICENSES/dependencies/rustc-demangle-0.1.28/LICENSE-MIT +25 -0
  221. package/LICENSES/dependencies/rustc-hash-2.1.3/LICENSE-APACHE +176 -0
  222. package/LICENSES/dependencies/rustc-hash-2.1.3/LICENSE-MIT +23 -0
  223. package/LICENSES/dependencies/rustc_version-0.4.1/LICENSE-APACHE +201 -0
  224. package/LICENSES/dependencies/rustc_version-0.4.1/LICENSE-MIT +25 -0
  225. package/LICENSES/dependencies/rustix-1.1.4/COPYRIGHT +29 -0
  226. package/LICENSES/dependencies/rustix-1.1.4/LICENSE-APACHE +201 -0
  227. package/LICENSES/dependencies/rustix-1.1.4/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
  228. package/LICENSES/dependencies/rustix-1.1.4/LICENSE-MIT +23 -0
  229. package/LICENSES/dependencies/rustversion-1.0.23/LICENSE-APACHE +176 -0
  230. package/LICENSES/dependencies/rustversion-1.0.23/LICENSE-MIT +23 -0
  231. package/LICENSES/dependencies/schemars-0.9.0/LICENSE +21 -0
  232. package/LICENSES/dependencies/schemars-1.2.2/LICENSE +21 -0
  233. package/LICENSES/dependencies/schemars_derive-1.2.2/LICENSE +21 -0
  234. package/LICENSES/dependencies/semver-1.0.28/LICENSE-APACHE +176 -0
  235. package/LICENSES/dependencies/semver-1.0.28/LICENSE-MIT +23 -0
  236. package/LICENSES/dependencies/serde-1.0.229/LICENSE-APACHE +176 -0
  237. package/LICENSES/dependencies/serde-1.0.229/LICENSE-MIT +23 -0
  238. package/LICENSES/dependencies/serde_core-1.0.229/LICENSE-APACHE +176 -0
  239. package/LICENSES/dependencies/serde_core-1.0.229/LICENSE-MIT +23 -0
  240. package/LICENSES/dependencies/serde_derive-1.0.229/LICENSE-APACHE +176 -0
  241. package/LICENSES/dependencies/serde_derive-1.0.229/LICENSE-MIT +23 -0
  242. package/LICENSES/dependencies/serde_derive_internals-0.30.0/LICENSE-APACHE +176 -0
  243. package/LICENSES/dependencies/serde_derive_internals-0.30.0/LICENSE-MIT +23 -0
  244. package/LICENSES/dependencies/serde_json-1.0.151/LICENSE-APACHE +176 -0
  245. package/LICENSES/dependencies/serde_json-1.0.151/LICENSE-MIT +23 -0
  246. package/LICENSES/dependencies/serde_with-3.23.0/LICENSE-APACHE +201 -0
  247. package/LICENSES/dependencies/serde_with-3.23.0/LICENSE-MIT +25 -0
  248. package/LICENSES/dependencies/serde_with_macros-3.23.0/LICENSE-APACHE +201 -0
  249. package/LICENSES/dependencies/serde_with_macros-3.23.0/LICENSE-MIT +25 -0
  250. package/LICENSES/dependencies/shell-words-1.1.1/LICENSE-APACHE +201 -0
  251. package/LICENSES/dependencies/shell-words-1.1.1/LICENSE-MIT +25 -0
  252. package/LICENSES/dependencies/shlex-2.0.1/LICENSE-APACHE +13 -0
  253. package/LICENSES/dependencies/shlex-2.0.1/LICENSE-MIT +21 -0
  254. package/LICENSES/dependencies/signal-hook-registry-1.4.8/LICENSE-APACHE +201 -0
  255. package/LICENSES/dependencies/signal-hook-registry-1.4.8/LICENSE-MIT +25 -0
  256. package/LICENSES/dependencies/slab-0.4.12/LICENSE +25 -0
  257. package/LICENSES/dependencies/smallvec-1.16.0/LICENSE-APACHE +201 -0
  258. package/LICENSES/dependencies/smallvec-1.16.0/LICENSE-MIT +25 -0
  259. package/LICENSES/dependencies/socket2-0.6.5/LICENSE-APACHE +201 -0
  260. package/LICENSES/dependencies/socket2-0.6.5/LICENSE-MIT +25 -0
  261. package/LICENSES/dependencies/stable_deref_trait-1.2.1/LICENSE-APACHE +201 -0
  262. package/LICENSES/dependencies/stable_deref_trait-1.2.1/LICENSE-MIT +25 -0
  263. package/LICENSES/dependencies/strsim-0.11.1/LICENSE +23 -0
  264. package/LICENSES/dependencies/strum-0.28.0/LICENSE +21 -0
  265. package/LICENSES/dependencies/strum_macros-0.28.0/LICENSE +21 -0
  266. package/LICENSES/dependencies/syn-2.0.119/LICENSE-APACHE +176 -0
  267. package/LICENSES/dependencies/syn-2.0.119/LICENSE-MIT +23 -0
  268. package/LICENSES/dependencies/syn-3.0.5/LICENSE-APACHE +176 -0
  269. package/LICENSES/dependencies/syn-3.0.5/LICENSE-MIT +23 -0
  270. package/LICENSES/dependencies/thiserror-2.0.20/LICENSE-APACHE +176 -0
  271. package/LICENSES/dependencies/thiserror-2.0.20/LICENSE-MIT +23 -0
  272. package/LICENSES/dependencies/thiserror-impl-2.0.20/LICENSE-APACHE +176 -0
  273. package/LICENSES/dependencies/thiserror-impl-2.0.20/LICENSE-MIT +23 -0
  274. package/LICENSES/dependencies/time-0.3.55/LICENSE-Apache +177 -0
  275. package/LICENSES/dependencies/time-0.3.55/LICENSE-MIT +19 -0
  276. package/LICENSES/dependencies/time-core-0.1.9/LICENSE-Apache +177 -0
  277. package/LICENSES/dependencies/time-core-0.1.9/LICENSE-MIT +19 -0
  278. package/LICENSES/dependencies/time-macros-0.2.32/LICENSE-Apache +177 -0
  279. package/LICENSES/dependencies/time-macros-0.2.32/LICENSE-MIT +19 -0
  280. package/LICENSES/dependencies/tinyvec-1.13.2/LICENSE-APACHE.md +202 -0
  281. package/LICENSES/dependencies/tinyvec-1.13.2/LICENSE-MIT.md +5 -0
  282. package/LICENSES/dependencies/tinyvec-1.13.2/LICENSE-ZLIB.md +11 -0
  283. package/LICENSES/dependencies/tinyvec_macros-0.1.1/LICENSE-APACHE.md +202 -0
  284. package/LICENSES/dependencies/tinyvec_macros-0.1.1/LICENSE-MIT.md +21 -0
  285. package/LICENSES/dependencies/tinyvec_macros-0.1.1/LICENSE-ZLIB.md +20 -0
  286. package/LICENSES/dependencies/tokio-1.53.1/LICENSE +21 -0
  287. package/LICENSES/dependencies/tokio-macros-2.7.2/LICENSE +22 -0
  288. package/LICENSES/dependencies/tracing-0.1.44/LICENSE +25 -0
  289. package/LICENSES/dependencies/tracing-attributes-0.1.31/LICENSE +25 -0
  290. package/LICENSES/dependencies/tracing-core-0.1.36/LICENSE +25 -0
  291. package/LICENSES/dependencies/unicode-ident-1.0.24/LICENSE-APACHE +176 -0
  292. package/LICENSES/dependencies/unicode-ident-1.0.24/LICENSE-MIT +23 -0
  293. package/LICENSES/dependencies/unicode-ident-1.0.24/LICENSE-UNICODE +39 -0
  294. package/LICENSES/dependencies/unicode-segmentation-1.13.3/COPYRIGHT +7 -0
  295. package/LICENSES/dependencies/unicode-segmentation-1.13.3/LICENSE-APACHE +201 -0
  296. package/LICENSES/dependencies/unicode-segmentation-1.13.3/LICENSE-MIT +25 -0
  297. package/LICENSES/dependencies/unicode-xid-0.2.6/COPYRIGHT +7 -0
  298. package/LICENSES/dependencies/unicode-xid-0.2.6/LICENSE-APACHE +201 -0
  299. package/LICENSES/dependencies/unicode-xid-0.2.6/LICENSE-MIT +25 -0
  300. package/LICENSES/dependencies/uuid-1.26.1/LICENSE-APACHE +201 -0
  301. package/LICENSES/dependencies/uuid-1.26.1/LICENSE-MIT +26 -0
  302. package/LICENSES/dependencies/walrus-0.26.5/LICENSE-APACHE +201 -0
  303. package/LICENSES/dependencies/walrus-0.26.5/LICENSE-MIT +25 -0
  304. package/LICENSES/dependencies/walrus-macro-0.26.0/LICENSE-APACHE +201 -0
  305. package/LICENSES/dependencies/walrus-macro-0.26.0/LICENSE-MIT +25 -0
  306. package/LICENSES/dependencies/wasi-0.11.1+wasi-snapshot-preview1/LICENSE-APACHE +201 -0
  307. package/LICENSES/dependencies/wasi-0.11.1+wasi-snapshot-preview1/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
  308. package/LICENSES/dependencies/wasi-0.11.1+wasi-snapshot-preview1/LICENSE-MIT +23 -0
  309. package/LICENSES/dependencies/wasm-bindgen-0.2.128/LICENSE-APACHE +201 -0
  310. package/LICENSES/dependencies/wasm-bindgen-0.2.128/LICENSE-MIT +25 -0
  311. package/LICENSES/dependencies/wasm-bindgen-cli-support-0.2.128/LICENSE-APACHE +201 -0
  312. package/LICENSES/dependencies/wasm-bindgen-cli-support-0.2.128/LICENSE-MIT +25 -0
  313. package/LICENSES/dependencies/wasm-bindgen-macro-0.2.128/LICENSE-APACHE +201 -0
  314. package/LICENSES/dependencies/wasm-bindgen-macro-0.2.128/LICENSE-MIT +25 -0
  315. package/LICENSES/dependencies/wasm-bindgen-macro-support-0.2.128/LICENSE-APACHE +201 -0
  316. package/LICENSES/dependencies/wasm-bindgen-macro-support-0.2.128/LICENSE-MIT +25 -0
  317. package/LICENSES/dependencies/wasm-bindgen-shared-0.2.128/LICENSE-APACHE +201 -0
  318. package/LICENSES/dependencies/wasm-bindgen-shared-0.2.128/LICENSE-MIT +25 -0
  319. package/LICENSES/dependencies/wasm-encoder-0.245.1/LICENSE-APACHE +201 -0
  320. package/LICENSES/dependencies/wasm-encoder-0.245.1/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
  321. package/LICENSES/dependencies/wasm-encoder-0.245.1/LICENSE-MIT +23 -0
  322. package/LICENSES/dependencies/wasmparser-0.245.1/LICENSE-APACHE +201 -0
  323. package/LICENSES/dependencies/wasmparser-0.245.1/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
  324. package/LICENSES/dependencies/wasmparser-0.245.1/LICENSE-MIT +23 -0
  325. package/LICENSES/dependencies/windows-core-0.62.2/license-apache-2.0 +201 -0
  326. package/LICENSES/dependencies/windows-core-0.62.2/license-mit +21 -0
  327. package/LICENSES/dependencies/windows-implement-0.60.2/license-apache-2.0 +201 -0
  328. package/LICENSES/dependencies/windows-implement-0.60.2/license-mit +21 -0
  329. package/LICENSES/dependencies/windows-interface-0.59.3/license-apache-2.0 +201 -0
  330. package/LICENSES/dependencies/windows-interface-0.59.3/license-mit +21 -0
  331. package/LICENSES/dependencies/windows-link-0.2.1/license-apache-2.0 +201 -0
  332. package/LICENSES/dependencies/windows-link-0.2.1/license-mit +21 -0
  333. package/LICENSES/dependencies/windows-result-0.4.1/license-apache-2.0 +201 -0
  334. package/LICENSES/dependencies/windows-result-0.4.1/license-mit +21 -0
  335. package/LICENSES/dependencies/windows-strings-0.5.1/license-apache-2.0 +201 -0
  336. package/LICENSES/dependencies/windows-strings-0.5.1/license-mit +21 -0
  337. package/LICENSES/dependencies/windows-sys-0.61.2/license-apache-2.0 +201 -0
  338. package/LICENSES/dependencies/windows-sys-0.61.2/license-mit +21 -0
  339. package/LICENSES/dependencies/zmij-1.0.23/LICENSE-MIT +23 -0
  340. package/README.md +70 -0
  341. package/THIRD-PARTY.md +62 -0
  342. package/package.json +48 -9
  343. package/source/.cargo/config.toml +5 -0
  344. package/source/.ci/upstream-notices/PROVENANCE.json +198 -0
  345. package/source/.ci/upstream-notices/agent-client-protocol-2.1.0/LICENSE +191 -0
  346. package/source/.ci/upstream-notices/agent-client-protocol-derive-2.1.0/LICENSE +191 -0
  347. package/source/.ci/upstream-notices/agent-client-protocol-schema-1.7.0/LICENSE +190 -0
  348. package/source/.ci/upstream-notices/defmt-parser-1.0.0/LICENSE-APACHE +201 -0
  349. package/source/.ci/upstream-notices/defmt-parser-1.0.0/LICENSE-MIT +25 -0
  350. package/source/.ci/upstream-notices/r-efi-6.0.0/AUTHORS +75 -0
  351. package/source/.ci/upstream-notices/wasm-encoder-0.245.1/LICENSE-APACHE +201 -0
  352. package/source/.ci/upstream-notices/wasm-encoder-0.245.1/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
  353. package/source/.ci/upstream-notices/wasm-encoder-0.245.1/LICENSE-MIT +23 -0
  354. package/source/.ci/upstream-notices/wasmparser-0.245.1/LICENSE-APACHE +201 -0
  355. package/source/.ci/upstream-notices/wasmparser-0.245.1/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
  356. package/source/.ci/upstream-notices/wasmparser-0.245.1/LICENSE-MIT +23 -0
  357. package/source/.ci/wasm-bundle/Cargo.toml +10 -0
  358. package/source/.ci/wasm-bundle/src/main.rs +17 -0
  359. package/source/CHANGELOG.md +99 -0
  360. package/source/Cargo.lock +1630 -0
  361. package/source/Cargo.toml +48 -0
  362. package/source/LICENSE +307 -0
  363. package/source/LICENSE.md +30 -0
  364. package/source/LICENSES/GPL-3.0-only.txt +232 -0
  365. package/source/LICENSES/LGPL-3.0-linking-exception.txt +16 -0
  366. package/source/LICENSES/LGPL-3.0-only WITH LGPL-3.0-linking-exception.txt +16 -0
  367. package/source/LICENSES/LGPL-3.0-only.txt +304 -0
  368. package/source/README.md +289 -0
  369. package/source/THIRD-PARTY.md +62 -0
  370. package/source/dependencies.tar.gz +0 -0
  371. package/source/examples/native.rs +45 -0
  372. package/source/src/auth.rs +435 -0
  373. package/source/src/configuration.rs +140 -0
  374. package/source/src/conversation.rs +594 -0
  375. package/source/src/dock.rs +564 -0
  376. package/source/src/lib.rs +39 -0
  377. package/source/src/native/client.rs +401 -0
  378. package/source/src/native/drivers/codex.rs +506 -0
  379. package/source/src/native/drivers/mod.rs +305 -0
  380. package/source/src/native/drivers/opencode.rs +531 -0
  381. package/source/src/native/env.rs +264 -0
  382. package/source/src/native/fixture.py +191 -0
  383. package/source/src/native/mod.rs +257 -0
  384. package/source/src/native/pool.rs +440 -0
  385. package/source/src/native/session.rs +609 -0
  386. package/source/src/native/tests.rs +667 -0
  387. package/source/src/transport.rs +330 -0
  388. package/source/src/web.rs +35 -0
  389. package/src/auth.test.ts +115 -0
  390. package/src/components/ChatDock.component.test.ts +213 -0
  391. package/src/components/ChatDock.svelte +422 -0
  392. package/src/components/Dock.component.test.ts +92 -0
  393. package/src/components/Dock.svelte +6 -3
  394. package/src/components/StepConfig.component.test.ts +185 -0
  395. package/src/components/StepConfig.svelte +247 -0
  396. package/src/dock.test.ts +226 -0
  397. package/wasm/ccht_bg.wasm +0 -0
@@ -0,0 +1,330 @@
1
+ //! Transport abstraction for ACP-style JSON-RPC.
2
+ //!
3
+ //! The same event contract can travel over a native stdio pipe or over a
4
+ //! socket used by a Wasm bridge. This module only describes and validates
5
+ //! endpoints; it never connects, spawns processes, or performs network I/O.
6
+ //!
7
+ //! Validation is offline and never echoes addresses or credentials: error
8
+ //! messages use fixed text so secrets cannot leak through [`TransportError`].
9
+
10
+ /// How an ACP-style endpoint is reached.
11
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
12
+ pub enum TransportKind {
13
+ /// A child process speaking JSON-RPC over stdin and stdout.
14
+ Stdio,
15
+ /// A socket endpoint (`ws`/`wss`/`http`/`https`) used by a bridge.
16
+ Socket,
17
+ }
18
+
19
+ /// A validated endpoint description for ACP-style JSON-RPC.
20
+ ///
21
+ /// Implementors must be sendable across threads; validation is offline only
22
+ /// and performs no connecting or process spawning.
23
+ pub trait Transport: Send {
24
+ /// Which mechanism this endpoint uses.
25
+ fn kind(&self) -> TransportKind;
26
+ /// Non-sensitive hint for logs or UI, without credentials.
27
+ fn address_hint(&self) -> Option<String>;
28
+ /// Check endpoint shape without connecting or spawning.
29
+ ///
30
+ /// # Errors
31
+ ///
32
+ /// Returns [`TransportError`] when the endpoint shape is invalid.
33
+ fn validate(&self) -> Result<(), TransportError>;
34
+ }
35
+
36
+ /// Transport validation failure without sensitive data.
37
+ ///
38
+ /// Messages are fixed strings; they never echo programs, URLs, or tokens.
39
+ #[derive(Debug, Clone, thiserror::Error, PartialEq, Eq)]
40
+ pub enum TransportError {
41
+ /// The endpoint address shape is invalid.
42
+ #[error("invalid transport address: {0}")]
43
+ InvalidAddress(&'static str),
44
+ /// This transport kind is not supported in the current context.
45
+ #[error("unsupported transport: {0}")]
46
+ Unsupported(&'static str),
47
+ /// The transport is already closed.
48
+ #[error("transport is closed")]
49
+ Closed,
50
+ }
51
+
52
+ /// Stdio endpoint: an explicit program plus arguments.
53
+ ///
54
+ /// No shell parsing is involved; the program must be non-empty.
55
+ #[derive(Debug, Clone, PartialEq, Eq)]
56
+ pub struct StdioTransport {
57
+ /// Explicit executable path or name; never a shell string.
58
+ pub program: String,
59
+ /// Arguments passed directly to the executable.
60
+ pub args: Vec<String>,
61
+ }
62
+
63
+ impl StdioTransport {
64
+ /// Create a stdio endpoint with an explicit program and arguments.
65
+ pub fn new(program: impl Into<String>, args: Vec<String>) -> Self {
66
+ Self {
67
+ program: program.into(),
68
+ args,
69
+ }
70
+ }
71
+ }
72
+
73
+ impl Transport for StdioTransport {
74
+ /// Report [`TransportKind::Stdio`].
75
+ fn kind(&self) -> TransportKind {
76
+ TransportKind::Stdio
77
+ }
78
+
79
+ /// The program name when non-empty, without arguments.
80
+ fn address_hint(&self) -> Option<String> {
81
+ let program = self.program.trim();
82
+ if program.is_empty() {
83
+ None
84
+ } else {
85
+ Some(program.to_owned())
86
+ }
87
+ }
88
+
89
+ /// Require a non-empty program; arguments need no validation.
90
+ ///
91
+ /// # Errors
92
+ ///
93
+ /// Returns [`TransportError::InvalidAddress`] when the program is empty.
94
+ fn validate(&self) -> Result<(), TransportError> {
95
+ if self.program.trim().is_empty() {
96
+ return Err(TransportError::InvalidAddress(
97
+ "stdio program must not be empty",
98
+ ));
99
+ }
100
+ Ok(())
101
+ }
102
+ }
103
+
104
+ /// Socket endpoint: a URL string validated offline, never dialed.
105
+ ///
106
+ /// Accepted schemes are `ws`, `wss`, `http`, and `https` with a non-empty
107
+ /// host. Validation checks shape only and never connects.
108
+ #[derive(Debug, Clone, PartialEq, Eq)]
109
+ pub struct SocketTransport {
110
+ /// Endpoint URL; validated for shape only, never connected.
111
+ pub url: String,
112
+ }
113
+
114
+ impl SocketTransport {
115
+ /// Create a socket endpoint; call [`Transport::validate`] to check shape.
116
+ pub fn new(url: impl Into<String>) -> Self {
117
+ Self { url: url.into() }
118
+ }
119
+ }
120
+
121
+ impl Transport for SocketTransport {
122
+ /// Report [`TransportKind::Socket`].
123
+ fn kind(&self) -> TransportKind {
124
+ TransportKind::Socket
125
+ }
126
+
127
+ /// The URL when non-empty; callers must redact userinfo before display
128
+ /// when the URL may carry credentials.
129
+ fn address_hint(&self) -> Option<String> {
130
+ if self.url.trim().is_empty() {
131
+ None
132
+ } else {
133
+ Some(self.url.clone())
134
+ }
135
+ }
136
+
137
+ /// Validate scheme and host presence without connecting.
138
+ ///
139
+ /// # Errors
140
+ ///
141
+ /// Returns [`TransportError::InvalidAddress`] when the scheme is not
142
+ /// `ws`/`wss`/`http`/`https` or when no host is present.
143
+ fn validate(&self) -> Result<(), TransportError> {
144
+ validate_socket_url(&self.url)
145
+ }
146
+ }
147
+
148
+ /// Check socket URL shape without connecting or echoing the URL in errors.
149
+ fn validate_socket_url(url: &str) -> Result<(), TransportError> {
150
+ if url.trim().is_empty() {
151
+ return Err(TransportError::InvalidAddress(
152
+ "socket url must not be empty",
153
+ ));
154
+ }
155
+ if url != url.trim() || url.chars().any(char::is_whitespace) {
156
+ return Err(TransportError::InvalidAddress(
157
+ "socket url must not contain whitespace",
158
+ ));
159
+ }
160
+ let Some((scheme, rest)) = url.split_once("://") else {
161
+ return Err(TransportError::InvalidAddress(
162
+ "socket url must include a scheme",
163
+ ));
164
+ };
165
+ match scheme.to_ascii_lowercase().as_str() {
166
+ "ws" | "wss" | "http" | "https" => {}
167
+ _ => {
168
+ return Err(TransportError::InvalidAddress(
169
+ "socket url scheme must be ws, wss, http, or https",
170
+ ));
171
+ }
172
+ }
173
+ if rest.is_empty() {
174
+ return Err(TransportError::InvalidAddress(
175
+ "socket url must include a host",
176
+ ));
177
+ }
178
+ let authority = rest.split(['/', '?', '#']).next().unwrap_or("");
179
+ if authority.is_empty() {
180
+ return Err(TransportError::InvalidAddress(
181
+ "socket url must include a host",
182
+ ));
183
+ }
184
+ let host_port = authority.rsplit('@').next().unwrap_or("");
185
+ let host = if let Some(bracketed) = host_port.strip_prefix('[') {
186
+ let Some(end) = bracketed.find(']') else {
187
+ return Err(TransportError::InvalidAddress(
188
+ "socket url must include a host",
189
+ ));
190
+ };
191
+ &bracketed[..end]
192
+ } else {
193
+ host_port.split(':').next().unwrap_or("")
194
+ };
195
+ if host.is_empty() {
196
+ return Err(TransportError::InvalidAddress(
197
+ "socket url must include a host",
198
+ ));
199
+ }
200
+ Ok(())
201
+ }
202
+
203
+ #[cfg(test)]
204
+ mod tests {
205
+ use super::*;
206
+
207
+ fn assert_send<T: Send>() {}
208
+
209
+ #[test]
210
+ fn transports_are_send() {
211
+ assert_send::<StdioTransport>();
212
+ assert_send::<SocketTransport>();
213
+ assert_send::<TransportKind>();
214
+ assert_send::<TransportError>();
215
+ }
216
+
217
+ #[test]
218
+ fn stdio_accepts_explicit_program() {
219
+ let transport = StdioTransport::new("agent", vec!["--flag".into()]);
220
+ assert_eq!(transport.kind(), TransportKind::Stdio);
221
+ assert_eq!(transport.address_hint().as_deref(), Some("agent"));
222
+ transport.validate().unwrap();
223
+ }
224
+
225
+ #[test]
226
+ fn stdio_rejects_empty_program() {
227
+ for program in ["", " ", "\t\n"] {
228
+ let transport = StdioTransport::new(program, Vec::new());
229
+ assert_eq!(transport.address_hint(), None);
230
+ assert_eq!(
231
+ transport.validate().unwrap_err(),
232
+ TransportError::InvalidAddress("stdio program must not be empty")
233
+ );
234
+ }
235
+ }
236
+
237
+ #[test]
238
+ fn socket_accepts_supported_schemes_with_host() {
239
+ for url in [
240
+ "ws://bridge.local/session",
241
+ "wss://bridge.example.com:443/session",
242
+ "http://localhost:8080/bridge",
243
+ "https://example.com",
244
+ "ws://127.0.0.1:9000",
245
+ "wss://[::1]:9000/session",
246
+ "https://example.com/path?query=1#fragment",
247
+ ] {
248
+ let transport = SocketTransport::new(url);
249
+ assert_eq!(transport.kind(), TransportKind::Socket);
250
+ assert_eq!(transport.address_hint().as_deref(), Some(url));
251
+ transport.validate().unwrap();
252
+ }
253
+ }
254
+
255
+ #[test]
256
+ fn socket_scheme_match_is_case_insensitive() {
257
+ SocketTransport::new("WSS://bridge.example.com/session")
258
+ .validate()
259
+ .unwrap();
260
+ }
261
+
262
+ #[test]
263
+ fn socket_rejects_missing_or_unsupported_address() {
264
+ for url in [
265
+ "",
266
+ " ",
267
+ "bridge.example.com/session",
268
+ "ftp://bridge.example.com/session",
269
+ "file:///tmp/socket",
270
+ "ws://",
271
+ "wss://",
272
+ "https://",
273
+ "ws:///path-only",
274
+ "https:///path-only",
275
+ "ws://?query-only",
276
+ "ws://#fragment-only",
277
+ "ws://:8080/no-host",
278
+ "ws://bridge.example.com:8080/pa th",
279
+ " ws://bridge.example.com",
280
+ "ws://bridge.example.com ",
281
+ ] {
282
+ let transport = SocketTransport::new(url);
283
+ assert!(
284
+ transport.validate().is_err(),
285
+ "expected rejection for {url:?}"
286
+ );
287
+ }
288
+ }
289
+
290
+ #[test]
291
+ fn error_messages_never_echo_addresses() {
292
+ let secret = "super-secret-token-9f8e7d6c";
293
+ let transport = SocketTransport::new(format!("ftp://bridge.example.com/{secret}"));
294
+ let error = transport.validate().unwrap_err();
295
+ assert_eq!(
296
+ error,
297
+ TransportError::InvalidAddress("socket url scheme must be ws, wss, http, or https")
298
+ );
299
+ let rendered = format!("{error} {error:?}");
300
+ assert!(!rendered.contains(secret));
301
+ assert!(!rendered.contains("ftp://"));
302
+
303
+ let stdio_error = StdioTransport::new("", Vec::new()).validate().unwrap_err();
304
+ assert!(!format!("{stdio_error}").contains(secret));
305
+ }
306
+
307
+ #[test]
308
+ fn closed_and_unsupported_variants_stay_static() {
309
+ let closed = TransportError::Closed;
310
+ let unsupported = TransportError::Unsupported("socket bridge");
311
+ assert_eq!(format!("{closed}"), "transport is closed");
312
+ assert_eq!(
313
+ format!("{unsupported}"),
314
+ "unsupported transport: socket bridge"
315
+ );
316
+ }
317
+
318
+ #[test]
319
+ fn socket_hint_is_none_for_blank_address() {
320
+ for url in ["", " ", "\t\n"] {
321
+ assert_eq!(SocketTransport::new(url).address_hint(), None);
322
+ }
323
+ }
324
+
325
+ #[test]
326
+ fn stdio_hint_trims_program_name() {
327
+ let transport = StdioTransport::new(" agent ", Vec::new());
328
+ assert_eq!(transport.address_hint().as_deref(), Some("agent"));
329
+ }
330
+ }
@@ -0,0 +1,35 @@
1
+ //! Browser bindings for the same conversation state used by native consumers.
2
+
3
+ use wasm_bindgen::prelude::*;
4
+
5
+ /// A Rust conversation model exported to JavaScript. The application owns transport.
6
+ #[wasm_bindgen(js_name = ConversationModel)]
7
+ pub struct WebConversation {
8
+ inner: crate::Conversation,
9
+ }
10
+
11
+ #[wasm_bindgen(js_class = ConversationModel)]
12
+ impl WebConversation {
13
+ /// Create an isolated conversation state.
14
+ #[wasm_bindgen(constructor)]
15
+ pub fn new(conversation_id: String) -> Self {
16
+ Self {
17
+ inner: crate::Conversation::new(conversation_id),
18
+ }
19
+ }
20
+
21
+ /// Apply an event and report whether it changed the state.
22
+ #[wasm_bindgen(js_name = applyEvent)]
23
+ pub fn apply_event(&mut self, event_json: &str) -> Result<bool, JsValue> {
24
+ self.inner
25
+ .apply_json(event_json)
26
+ .map_err(|error| JsValue::from_str(&error.to_string()))
27
+ }
28
+
29
+ /// Return the current render state as JSON.
30
+ pub fn snapshot(&self) -> Result<String, JsValue> {
31
+ self.inner
32
+ .snapshot_json()
33
+ .map_err(|error| JsValue::from_str(&error.to_string()))
34
+ }
35
+ }
@@ -0,0 +1,115 @@
1
+ /** Contract tests for the web auth mirrors (web/src/auth.ts).
2
+ *
3
+ * Covers the Rust `AuthState` shape validation, the authenticated/account
4
+ * projections, and the render-gate for device-code challenges. Fixtures
5
+ * only; no DOM, network, or storage.
6
+ */
7
+ import { describe, expect, test } from 'bun:test';
8
+ import { authAccount, isAuthenticated, isAuthState, parseAuthState, validateChallenge } from './auth.ts';
9
+
10
+ describe('isAuthenticated', () => {
11
+ test('only the authenticated object shape counts', () => {
12
+ expect(isAuthenticated('unknown')).toBe(false);
13
+ expect(isAuthenticated('unauthenticated')).toBe(false);
14
+ expect(isAuthenticated({ authenticated: {} })).toBe(true);
15
+ expect(isAuthenticated({ authenticated: { account: null } })).toBe(true);
16
+ expect(isAuthenticated({ authenticated: { account: 'julian' } })).toBe(true);
17
+ });
18
+ });
19
+
20
+ describe('authAccount', () => {
21
+ test('returns the display label or null', () => {
22
+ expect(authAccount('unknown')).toBeNull();
23
+ expect(authAccount('unauthenticated')).toBeNull();
24
+ expect(authAccount({ authenticated: {} })).toBeNull();
25
+ expect(authAccount({ authenticated: { account: null } })).toBeNull();
26
+ expect(authAccount({ authenticated: { account: 'julian' } })).toBe('julian');
27
+ });
28
+ });
29
+
30
+ describe('parseAuthState / isAuthState', () => {
31
+ test('accepts the exact Rust JSON shapes', () => {
32
+ expect(parseAuthState('unknown')).toBe('unknown');
33
+ expect(parseAuthState('unauthenticated')).toBe('unauthenticated');
34
+ expect(parseAuthState({ authenticated: {} })).toEqual({ authenticated: {} });
35
+ expect(parseAuthState({ authenticated: { account: null } })).toEqual({
36
+ authenticated: { account: null },
37
+ });
38
+ expect(parseAuthState({ authenticated: { account: 'a' } })).toEqual({
39
+ authenticated: { account: 'a' },
40
+ });
41
+ expect(parseAuthState(JSON.parse(JSON.stringify({ authenticated: { account: 'a' } })))).toEqual({
42
+ authenticated: { account: 'a' },
43
+ });
44
+ });
45
+
46
+ test('ignores unknown fields inside the inner object like serde', () => {
47
+ expect(parseAuthState({ authenticated: { account: 'a', extra: 1 } })).toEqual({
48
+ authenticated: { account: 'a' },
49
+ });
50
+ });
51
+
52
+ test('rejects everything else with a TypeError', () => {
53
+ for (const value of [
54
+ null,
55
+ undefined,
56
+ 0,
57
+ true,
58
+ [],
59
+ {},
60
+ { authenticated: null },
61
+ { authenticated: 42 },
62
+ { authenticated: { account: 42 } },
63
+ { authenticated: { account: {} } },
64
+ { unknown: {} },
65
+ { authenticated: {}, extra: 1 },
66
+ 'UNKNOWN',
67
+ 'authenticated',
68
+ ]) {
69
+ expect(() => parseAuthState(value)).toThrow(TypeError);
70
+ expect(isAuthState(value)).toBe(false);
71
+ }
72
+ expect(isAuthState('unknown')).toBe(true);
73
+ expect(isAuthState({ authenticated: { account: 'a' } })).toBe(true);
74
+ });
75
+
76
+ test('never throws on hostile input', () => {
77
+ expect(() => isAuthState(Object.create(null))).not.toThrow();
78
+ });
79
+ });
80
+
81
+ describe('validateChallenge', () => {
82
+ const good = { verification_url: 'https://auth.openai.com/codex/device', user_code: 'TEST-4826' };
83
+
84
+ test('accepts a well-formed challenge', () => {
85
+ expect(validateChallenge(good)).toBe(true);
86
+ expect(validateChallenge({ ...good, user_code: 'a'.repeat(64) })).toBe(true);
87
+ expect(validateChallenge({ ...good, verification_url: 'https://example.com/x?y=1' })).toBe(true);
88
+ expect(validateChallenge({ ...good, extra: 'ignored' })).toBe(true);
89
+ });
90
+
91
+ test('rejects malformed challenges without throwing', () => {
92
+ for (const value of [
93
+ null,
94
+ undefined,
95
+ 'code',
96
+ [],
97
+ {},
98
+ { verification_url: good.verification_url },
99
+ { user_code: good.user_code },
100
+ { verification_url: 42, user_code: good.user_code },
101
+ { ...good, user_code: '' },
102
+ { ...good, user_code: 'a'.repeat(65) },
103
+ { ...good, user_code: 'has space' },
104
+ { ...good, user_code: 'semi;colon' },
105
+ { ...good, user_code: 'uniçode' },
106
+ { ...good, verification_url: 'http://auth.openai.com/codex/device' },
107
+ { ...good, verification_url: 'not a url' },
108
+ { ...good, verification_url: 'https://user:pass@auth.openai.com/' },
109
+ { ...good, verification_url: 'https://' },
110
+ { ...good, verification_url: 'javascript:alert(1)' },
111
+ ]) {
112
+ expect(validateChallenge(value)).toBe(false);
113
+ }
114
+ });
115
+ });
@@ -0,0 +1,213 @@
1
+ /** Browser behavior of the generic bare chat panel (ChatDock.svelte).
2
+ *
3
+ * Covers welcome/message rendering, copy feedback, the send lifecycle
4
+ * (draft clear and restore, disabled gates, Enter/isComposing handling),
5
+ * Stop, history selection, activity gating, and status labels. The default
6
+ * activity renderer is exercised through fixture TurnState values.
7
+ */
8
+ import { render, fireEvent, cleanup } from '@testing-library/svelte';
9
+ import { afterEach, describe, expect, test, vi } from 'vitest';
10
+ import ChatDock from './ChatDock.svelte';
11
+
12
+ afterEach(() => cleanup());
13
+
14
+ const copy = {
15
+ kicker: 'Creator · diverges',
16
+ title: 'Brief the generator',
17
+ composerId: 'creator-prompt',
18
+ composerLabel: 'Message the creator',
19
+ composerPlaceholder: 'Describe the name you need…',
20
+ sendLabel: 'Send to creator',
21
+ welcomeTitle: 'creator',
22
+ welcomeBody: 'Talk through the problem first.',
23
+ welcomeExample: 'Try: short .ch names.',
24
+ };
25
+
26
+ function openChat(props: Record<string, unknown> = {}) {
27
+ return render(ChatDock, {
28
+ ...copy,
29
+ messages: [],
30
+ draft: '',
31
+ onSend: () => {},
32
+ ...props,
33
+ });
34
+ }
35
+
36
+ function turn(overrides: Record<string, unknown> = {}) {
37
+ return {
38
+ request_id: 'req-1',
39
+ last_sequence: 2,
40
+ text: 'hello',
41
+ user_text: '',
42
+ user_content: [],
43
+ thought_text: '',
44
+ thought_content: [],
45
+ content: [],
46
+ tools: {},
47
+ permissions: [],
48
+ updates: {},
49
+ status: 'completed',
50
+ stop_reason: 'end_turn',
51
+ error: null,
52
+ ...overrides,
53
+ };
54
+ }
55
+
56
+ describe('welcome and messages', () => {
57
+ test('empty thread shows the welcome article', () => {
58
+ const { getByText } = openChat();
59
+ expect(getByText('Talk through the problem first.')).toBeTruthy();
60
+ expect(getByText('Try: short .ch names.')).toBeTruthy();
61
+ });
62
+
63
+ test('user and assistant messages render with copy controls', async () => {
64
+ const onCopy = vi.fn();
65
+ const { getByText, getAllByRole } = openChat({
66
+ onCopy,
67
+ messages: [
68
+ { id: 'u1', role: 'user', content: 'a name' },
69
+ { id: 'a1', role: 'assistant', content: 'how about x', modelName: 'model-x' },
70
+ ],
71
+ });
72
+ expect(getByText('a name')).toBeTruthy();
73
+ expect(getByText('model-x')).toBeTruthy();
74
+ Object.defineProperty(navigator, 'clipboard', {
75
+ value: { writeText: vi.fn().mockResolvedValue(undefined) },
76
+ configurable: true,
77
+ });
78
+ await fireEvent.click(getAllByRole('button', { name: 'Copy' })[0]);
79
+ expect(onCopy).toHaveBeenCalledWith('u1', 'a name');
80
+ expect(getByText('Copied')).toBeTruthy();
81
+ });
82
+
83
+ test('assistant without activity offers Show activity only with a handler', () => {
84
+ const bare = openChat({ messages: [{ id: 'a1', role: 'assistant', content: 'hi', requestId: 'r1' }] });
85
+ expect(bare.queryByRole('button', { name: 'Show activity' })).toBeNull();
86
+ const wired = openChat({
87
+ onShowActivity: () => {},
88
+ messages: [{ id: 'a1', role: 'assistant', content: 'hi', requestId: 'r1' }],
89
+ });
90
+ expect(wired.getByRole('button', { name: 'Show activity' })).toBeTruthy();
91
+ });
92
+ });
93
+
94
+ describe('default activity renderer', () => {
95
+ test('covers reasoning, tools, usage, plan, permissions, error, and status', () => {
96
+ const { getByText } = openChat({
97
+ messages: [
98
+ {
99
+ id: 'a1',
100
+ role: 'assistant',
101
+ content: 'results',
102
+ activity: turn({
103
+ thought_text: 'thinking out loud',
104
+ tools: { t1: { toolCallId: 't1', title: 'Lookup', status: 'done', rawInput: { q: 1 } } },
105
+ updates: { usage_update: { used: 1200, size: 8000 }, plan: { entries: [{ content: 'step', status: 'done' }] } },
106
+ permissions: [{ request_id: 'p1', request: {} }],
107
+ error: { code: 'boom', message: 'went wrong' },
108
+ status: 'failed',
109
+ stop_reason: 'error',
110
+ }),
111
+ },
112
+ ],
113
+ });
114
+ expect(getByText('Reasoning')).toBeTruthy();
115
+ expect(getByText('thinking out loud')).toBeTruthy();
116
+ expect(getByText('Lookup · done')).toBeTruthy();
117
+ expect(getByText('Context: 1,200 / 8,000 tokens')).toBeTruthy();
118
+ expect(getByText('Plan')).toBeTruthy();
119
+ expect(getByText(/1 permission request pending: p1/)).toBeTruthy();
120
+ expect(getByText('boom: went wrong')).toBeTruthy();
121
+ expect(getByText('Failed')).toBeTruthy();
122
+ expect(getByText(/· error/)).toBeTruthy();
123
+ });
124
+
125
+ test('status labels cover every turn state', () => {
126
+ const cases: Array<[string, string]> = [
127
+ ['streaming', 'Responding…'],
128
+ ['awaiting_permission', 'Needs approval'],
129
+ ['completed', 'Done'],
130
+ ['cancelled', 'Stopped'],
131
+ ['refused', 'Declined'],
132
+ ['failed', 'Failed'],
133
+ ];
134
+ for (const [status, label] of cases) {
135
+ const view = openChat({ messages: [{ id: 'a1', role: 'assistant', content: 'x', activity: turn({ status }) }] });
136
+ expect(view.getByText(label)).toBeTruthy();
137
+ view.unmount();
138
+ }
139
+ });
140
+ });
141
+
142
+ describe('composer', () => {
143
+ test('send clears the draft and forwards trimmed text', async () => {
144
+ const onSend = vi.fn();
145
+ const { getByLabelText, getByRole } = openChat({ draft: ' hello ', onSend });
146
+ await fireEvent.click(getByRole('button', { name: 'Send to creator' }));
147
+ expect(onSend).toHaveBeenCalledWith('hello');
148
+ expect((getByLabelText('Message the creator') as HTMLTextAreaElement).value).toBe('');
149
+ });
150
+
151
+ test('rejected send restores the draft', async () => {
152
+ const { getByLabelText, getByRole } = openChat({ draft: 'keep me', onSend: () => Promise.reject(new Error('down')) });
153
+ await fireEvent.click(getByRole('button', { name: 'Send to creator' }));
154
+ await new Promise((resolve) => setTimeout(resolve, 0));
155
+ expect((getByLabelText('Message the creator') as HTMLTextAreaElement).value).toBe('keep me');
156
+ });
157
+
158
+ test('send is gated on canSend, loading, and blank drafts', () => {
159
+ for (const props of [{ draft: 'x', canSend: false }, { draft: 'x', controlsLoading: true }, { draft: ' ' }, { draft: 'x', submitting: true }]) {
160
+ const view = openChat(props);
161
+ expect(view.getByRole('button', { name: 'Send to creator' }).hasAttribute('disabled')).toBe(true);
162
+ view.unmount();
163
+ }
164
+ const ready = openChat({ draft: 'x' });
165
+ expect(ready.getByRole('button', { name: 'Send to creator' }).hasAttribute('disabled')).toBe(false);
166
+ });
167
+
168
+ test('Enter submits, shift+Enter and composing do not', async () => {
169
+ const onSend = vi.fn();
170
+ const { getByLabelText } = openChat({ draft: 'hi', onSend });
171
+ const box = getByLabelText('Message the creator');
172
+ await fireEvent.keyDown(box, { key: 'Enter', shiftKey: true });
173
+ await fireEvent.keyDown(box, { key: 'Enter', isComposing: true });
174
+ expect(onSend).not.toHaveBeenCalled();
175
+ await fireEvent.keyDown(box, { key: 'Enter' });
176
+ expect(onSend).toHaveBeenCalledWith('hi');
177
+ });
178
+
179
+ test('Stop appears only while submitting with a handler', () => {
180
+ expect(openChat({ submitting: true }).queryByRole('button', { name: 'Stop' })).toBeNull();
181
+ const onStop = vi.fn();
182
+ const view = openChat({ submitting: true, onStop });
183
+ expect(view.getByRole('button', { name: 'Stop' })).toBeTruthy();
184
+ });
185
+
186
+ test('composer honours the disabled flag', () => {
187
+ const { getByLabelText } = openChat({ composerDisabled: true });
188
+ expect((getByLabelText('Message the creator') as HTMLTextAreaElement).disabled).toBe(true);
189
+ });
190
+ });
191
+
192
+ describe('history', () => {
193
+ test('picker lists conversations and selects through the callback', async () => {
194
+ const onSelectHistory = vi.fn();
195
+ const { getByLabelText } = openChat({
196
+ showHistoryPicker: true,
197
+ onSelectHistory,
198
+ activeHistoryId: 'c1',
199
+ history: [
200
+ { id: 'c1', title: 'First', message_count: 4 },
201
+ { id: 'c2', title: null, message_count: 1 },
202
+ ],
203
+ });
204
+ const select = getByLabelText('Conversation') as HTMLSelectElement;
205
+ expect(select.value).toBe('c1');
206
+ await fireEvent.change(select, { target: { value: 'c2' } });
207
+ expect(onSelectHistory).toHaveBeenCalledWith('c2');
208
+ });
209
+
210
+ test('no picker without the flag', () => {
211
+ expect(openChat().queryByLabelText('Conversation')).toBeNull();
212
+ });
213
+ });