@corbet-labs/ccht 0.2.2 → 0.2.3

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 (388) 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/THIRD-PARTY.md +62 -0
  341. package/package.json +37 -9
  342. package/source/.cargo/config.toml +5 -0
  343. package/source/.ci/upstream-notices/PROVENANCE.json +198 -0
  344. package/source/.ci/upstream-notices/agent-client-protocol-2.1.0/LICENSE +191 -0
  345. package/source/.ci/upstream-notices/agent-client-protocol-derive-2.1.0/LICENSE +191 -0
  346. package/source/.ci/upstream-notices/agent-client-protocol-schema-1.7.0/LICENSE +190 -0
  347. package/source/.ci/upstream-notices/defmt-parser-1.0.0/LICENSE-APACHE +201 -0
  348. package/source/.ci/upstream-notices/defmt-parser-1.0.0/LICENSE-MIT +25 -0
  349. package/source/.ci/upstream-notices/r-efi-6.0.0/AUTHORS +75 -0
  350. package/source/.ci/upstream-notices/wasm-encoder-0.245.1/LICENSE-APACHE +201 -0
  351. package/source/.ci/upstream-notices/wasm-encoder-0.245.1/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
  352. package/source/.ci/upstream-notices/wasm-encoder-0.245.1/LICENSE-MIT +23 -0
  353. package/source/.ci/upstream-notices/wasmparser-0.245.1/LICENSE-APACHE +201 -0
  354. package/source/.ci/upstream-notices/wasmparser-0.245.1/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
  355. package/source/.ci/upstream-notices/wasmparser-0.245.1/LICENSE-MIT +23 -0
  356. package/source/.ci/wasm-bundle/Cargo.toml +10 -0
  357. package/source/.ci/wasm-bundle/src/main.rs +17 -0
  358. package/source/CHANGELOG.md +85 -0
  359. package/source/Cargo.lock +1630 -0
  360. package/source/Cargo.toml +48 -0
  361. package/source/LICENSE +307 -0
  362. package/source/LICENSE.md +30 -0
  363. package/source/LICENSES/GPL-3.0-only.txt +232 -0
  364. package/source/LICENSES/LGPL-3.0-linking-exception.txt +16 -0
  365. package/source/LICENSES/LGPL-3.0-only WITH LGPL-3.0-linking-exception.txt +16 -0
  366. package/source/LICENSES/LGPL-3.0-only.txt +304 -0
  367. package/source/README.md +289 -0
  368. package/source/THIRD-PARTY.md +62 -0
  369. package/source/dependencies.tar.gz +0 -0
  370. package/source/examples/native.rs +45 -0
  371. package/source/src/auth.rs +435 -0
  372. package/source/src/configuration.rs +140 -0
  373. package/source/src/conversation.rs +594 -0
  374. package/source/src/dock.rs +564 -0
  375. package/source/src/lib.rs +39 -0
  376. package/source/src/native/client.rs +401 -0
  377. package/source/src/native/drivers/codex.rs +506 -0
  378. package/source/src/native/drivers/mod.rs +305 -0
  379. package/source/src/native/drivers/opencode.rs +531 -0
  380. package/source/src/native/env.rs +264 -0
  381. package/source/src/native/fixture.py +191 -0
  382. package/source/src/native/mod.rs +257 -0
  383. package/source/src/native/pool.rs +440 -0
  384. package/source/src/native/session.rs +609 -0
  385. package/source/src/native/tests.rs +667 -0
  386. package/source/src/transport.rs +330 -0
  387. package/source/src/web.rs +35 -0
  388. package/wasm/ccht_bg.wasm +0 -0
@@ -0,0 +1,667 @@
1
+ use super::*;
2
+ use crate::acp::{ContentBlock, SelectedPermissionOutcome, SessionUpdate, StopReason};
3
+ use crate::{Event, Prompt, SessionEvent};
4
+ use tokio::sync::mpsc;
5
+ use tokio::time::timeout;
6
+
7
+ fn options() -> NativeOptions {
8
+ NativeOptions {
9
+ operation_timeout: Duration::from_secs(5),
10
+ prompt_timeout: Duration::from_secs(5),
11
+ permission_timeout: Duration::from_secs(2),
12
+ shutdown_timeout: Duration::from_secs(2),
13
+ ..NativeOptions::default()
14
+ }
15
+ }
16
+
17
+ fn command(mode: &str) -> AgentCommand {
18
+ AgentCommand::new("python3").args(["-u", "-c", include_str!("fixture.py"), mode])
19
+ }
20
+
21
+ fn prompt(id: &str) -> Prompt {
22
+ Prompt {
23
+ request_id: id.into(),
24
+ content: vec!["test".into()],
25
+ }
26
+ }
27
+
28
+ async fn session(
29
+ mode: &str,
30
+ options: NativeOptions,
31
+ ) -> (
32
+ NativeClient,
33
+ NativeSession,
34
+ SessionHandle,
35
+ mpsc::Receiver<SessionEvent>,
36
+ ) {
37
+ let client = NativeClient::connect(command(mode), options).await.unwrap();
38
+ let mut session = client
39
+ .new_session(SessionOptions::new(std::env::temp_dir()))
40
+ .await
41
+ .unwrap();
42
+ let handle = session.handle();
43
+ let events = session.take_events().unwrap();
44
+ (client, session, handle, events)
45
+ }
46
+
47
+ fn text(event: &SessionEvent) -> Option<&str> {
48
+ match &event.event {
49
+ Event::Update {
50
+ update: SessionUpdate::AgentMessageChunk(chunk),
51
+ } => {
52
+ if let ContentBlock::Text(content) = &chunk.content {
53
+ Some(&content.text)
54
+ } else {
55
+ None
56
+ }
57
+ }
58
+ _ => None,
59
+ }
60
+ }
61
+
62
+ #[tokio::test]
63
+ async fn ordered_stream_and_multiple_turns_keep_one_session() {
64
+ let (client, _session, handle, mut events) = session("normal", options()).await;
65
+ for id in ["first", "second"] {
66
+ assert_eq!(
67
+ handle.prompt(prompt(id)).await.unwrap(),
68
+ StopReason::EndTurn
69
+ );
70
+ let first = events.recv().await.unwrap();
71
+ let second = events.recv().await.unwrap();
72
+ let completed = events.recv().await.unwrap();
73
+ assert_eq!(first.request_id.as_deref(), Some(id));
74
+ assert_eq!(text(&first), Some("hello "));
75
+ assert_eq!(text(&second), Some("world"));
76
+ assert!(matches!(
77
+ completed.event,
78
+ Event::Completed {
79
+ stop_reason: StopReason::EndTurn
80
+ }
81
+ ));
82
+ }
83
+ handle.close().await.unwrap();
84
+ assert!(events.recv().await.is_none());
85
+ client.close().await.unwrap();
86
+ }
87
+
88
+ #[tokio::test]
89
+ async fn default_permissions_deny_without_user_approval() {
90
+ let (client, _session, handle, mut events) = session("deny", options()).await;
91
+ handle.prompt(prompt("deny")).await.unwrap();
92
+ assert_eq!(text(&events.recv().await.unwrap()), Some("cancelled"));
93
+ assert!(matches!(
94
+ events.recv().await.unwrap().event,
95
+ Event::Completed { .. }
96
+ ));
97
+ client.close().await.unwrap();
98
+ }
99
+
100
+ #[tokio::test]
101
+ async fn permission_responses_are_validated_and_isolated_between_sessions() {
102
+ let mut options = options();
103
+ options.permissions = PermissionPolicy::Ask;
104
+ let (client, _first, handle, mut events) = session("ask", options).await;
105
+ let mut second = client
106
+ .new_session(SessionOptions::new(std::env::temp_dir()))
107
+ .await
108
+ .unwrap();
109
+ let other = second.handle();
110
+ let mut other_events = second.take_events().unwrap();
111
+ let first_prompt = tokio::spawn({
112
+ let handle = handle.clone();
113
+ async move { handle.prompt(prompt("first")).await }
114
+ });
115
+ let second_prompt = tokio::spawn({
116
+ let other = other.clone();
117
+ async move { other.prompt(prompt("second")).await }
118
+ });
119
+ let first_request = events.recv().await.unwrap();
120
+ let second_request = other_events.recv().await.unwrap();
121
+ let Event::Permission {
122
+ request_id,
123
+ request,
124
+ } = first_request.event
125
+ else {
126
+ panic!("permission event expected")
127
+ };
128
+ let Event::Permission {
129
+ request_id: second_id,
130
+ request: second_request,
131
+ } = second_request.event
132
+ else {
133
+ panic!("permission event expected")
134
+ };
135
+ assert_ne!(request.session_id, second_request.session_id);
136
+ assert_ne!(request_id, second_id);
137
+ assert_eq!(
138
+ other
139
+ .respond_permission(&request_id, PermissionDecision::Cancelled)
140
+ .await
141
+ .unwrap_err(),
142
+ NativeError::UnknownPermission
143
+ );
144
+ let invalid = PermissionDecision::Selected(SelectedPermissionOutcome::new("not-offered"));
145
+ assert_eq!(
146
+ handle
147
+ .respond_permission(&request_id, invalid)
148
+ .await
149
+ .unwrap_err(),
150
+ NativeError::InvalidPermissionOption
151
+ );
152
+ handle
153
+ .respond_permission(
154
+ &request_id,
155
+ PermissionDecision::Selected(SelectedPermissionOutcome::new("allow")),
156
+ )
157
+ .await
158
+ .unwrap();
159
+ assert_eq!(first_prompt.await.unwrap().unwrap(), StopReason::EndTurn);
160
+ assert!(!second_prompt.is_finished());
161
+ other
162
+ .respond_permission(&second_id, PermissionDecision::Cancelled)
163
+ .await
164
+ .unwrap();
165
+ assert_eq!(second_prompt.await.unwrap().unwrap(), StopReason::EndTurn);
166
+ assert_eq!(
167
+ handle
168
+ .respond_permission(&request_id, PermissionDecision::Cancelled)
169
+ .await
170
+ .unwrap_err(),
171
+ NativeError::UnknownPermission
172
+ );
173
+ client.close().await.unwrap();
174
+ }
175
+
176
+ #[tokio::test]
177
+ async fn active_prompt_rejects_overlap_and_cancels_cooperatively() {
178
+ let (client, _session, handle, mut events) = session("hang", options()).await;
179
+ let running = tokio::spawn({
180
+ let handle = handle.clone();
181
+ async move { handle.prompt(prompt("first")).await }
182
+ });
183
+ assert_eq!(text(&events.recv().await.unwrap()), Some("waiting"));
184
+ assert_eq!(
185
+ handle.prompt(prompt("overlap")).await.unwrap_err(),
186
+ NativeError::Busy
187
+ );
188
+ handle.cancel().await.unwrap();
189
+ assert_eq!(running.await.unwrap().unwrap(), StopReason::Cancelled);
190
+ assert!(matches!(
191
+ events.recv().await.unwrap().event,
192
+ Event::Completed {
193
+ stop_reason: StopReason::Cancelled
194
+ }
195
+ ));
196
+ client.close().await.unwrap();
197
+ }
198
+
199
+ #[tokio::test]
200
+ async fn ignored_cancellation_and_abandoned_prompts_close_the_connection() {
201
+ let mut limits = options();
202
+ limits.shutdown_timeout = Duration::from_millis(100);
203
+ let (client, _session, handle, mut events) = session("ignore_cancel", limits).await;
204
+ let running = tokio::spawn({
205
+ let handle = handle.clone();
206
+ async move { handle.prompt(prompt("first")).await }
207
+ });
208
+ events.recv().await.unwrap();
209
+ assert_eq!(handle.cancel().await.unwrap_err(), NativeError::Timeout);
210
+ assert!(running.await.unwrap().is_err());
211
+ assert!(
212
+ client
213
+ .new_session(SessionOptions::new(std::env::temp_dir()))
214
+ .await
215
+ .is_err()
216
+ );
217
+
218
+ let (client, _session, handle, mut events) = session("hang", options()).await;
219
+ let running = tokio::spawn({
220
+ let handle = handle.clone();
221
+ async move { handle.prompt(prompt("abandoned")).await }
222
+ });
223
+ events.recv().await.unwrap();
224
+ running.abort();
225
+ let _ = running.await;
226
+ assert!(
227
+ client
228
+ .new_session(SessionOptions::new(std::env::temp_dir()))
229
+ .await
230
+ .is_err()
231
+ );
232
+ }
233
+
234
+ #[tokio::test]
235
+ async fn restoration_preserves_history_before_new_prompt_identity() {
236
+ let client = NativeClient::connect(command("normal"), options())
237
+ .await
238
+ .unwrap();
239
+ let mut restored = client
240
+ .load_session("saved-session", SessionOptions::new(std::env::temp_dir()))
241
+ .await
242
+ .unwrap();
243
+ assert_eq!(restored.handle().id(), "saved-session");
244
+ let mut events = restored.take_events().unwrap();
245
+ let history = events.recv().await.unwrap();
246
+ assert_eq!(history.request_id, None);
247
+ assert_eq!(text(&history), Some("restored history"));
248
+ restored.handle().prompt(prompt("continued")).await.unwrap();
249
+ assert_eq!(
250
+ events.recv().await.unwrap().request_id.as_deref(),
251
+ Some("continued")
252
+ );
253
+ client.close().await.unwrap();
254
+ }
255
+
256
+ #[tokio::test]
257
+ async fn auth_errors_exclude_peer_secrets_and_unknown_host_requests_fail() {
258
+ let client = NativeClient::connect(command("auth_required"), options())
259
+ .await
260
+ .unwrap();
261
+ let error = match client
262
+ .new_session(SessionOptions::new(std::env::temp_dir()))
263
+ .await
264
+ {
265
+ Ok(_) => panic!("authentication failure expected"),
266
+ Err(error) => error,
267
+ };
268
+ assert_eq!(error, NativeError::AuthenticationRequired);
269
+ assert!(!format!("{error:?} {error}").contains("SECRET"));
270
+
271
+ let (client, _session, handle, mut events) =
272
+ session("unsupported_host_request", options()).await;
273
+ handle.prompt(prompt("unsupported")).await.unwrap();
274
+ assert_eq!(text(&events.recv().await.unwrap()), Some("unsupported"));
275
+ client.close().await.unwrap();
276
+ }
277
+
278
+ #[tokio::test]
279
+ async fn slow_consumers_fail_with_bounded_buffer_and_shutdown() {
280
+ let mut limits = options();
281
+ limits.event_capacity = 2;
282
+ let (client, _session, handle, _events) = session("burst", limits).await;
283
+ let result = timeout(Duration::from_secs(5), handle.prompt(prompt("overflow")))
284
+ .await
285
+ .unwrap();
286
+ assert_eq!(result.unwrap_err(), NativeError::EventBufferFull);
287
+ assert!(
288
+ client
289
+ .new_session(SessionOptions::new(std::env::temp_dir()))
290
+ .await
291
+ .is_err()
292
+ );
293
+ }
294
+
295
+ #[tokio::test]
296
+ async fn model_selection_is_explicit_and_api_key_overrides_are_rejected() {
297
+ let client = NativeClient::connect(command("normal"), options())
298
+ .await
299
+ .unwrap();
300
+ let mut selected = SessionOptions::new(std::env::temp_dir());
301
+ selected.model = Some("test-model".into());
302
+ let mut session = client.new_session(selected.clone()).await.unwrap();
303
+ let _events = session.take_events().unwrap();
304
+ session.handle().prompt(prompt("selected")).await.unwrap();
305
+ selected.model = Some("missing-model".into());
306
+ assert!(matches!(
307
+ client.new_session(selected).await,
308
+ Err(NativeError::Unsupported(_))
309
+ ));
310
+ client.close().await.unwrap();
311
+ let mut keyed = command("normal");
312
+ keyed
313
+ .env
314
+ .insert("OPENAI_API_KEY".into(), "not-a-real-key".into());
315
+ assert!(matches!(
316
+ NativeClient::connect(keyed, options()).await,
317
+ Err(NativeError::InvalidOptions(_))
318
+ ));
319
+ }
320
+
321
+ #[cfg(target_os = "linux")]
322
+ #[tokio::test]
323
+ async fn installed_launcher_sets_the_actual_startup_directory() {
324
+ let directory = std::env::temp_dir().canonicalize().unwrap();
325
+ let launch = command("startup_cwd")
326
+ .with_working_directory(&directory)
327
+ .unwrap();
328
+ let client = NativeClient::connect(launch, options()).await.unwrap();
329
+ let mut session = client
330
+ .new_session(SessionOptions::new(&directory))
331
+ .await
332
+ .unwrap();
333
+ let mut events = session.take_events().unwrap();
334
+ session.handle().prompt(prompt("cwd")).await.unwrap();
335
+ assert_eq!(text(&events.recv().await.unwrap()), directory.to_str());
336
+ client.close().await.unwrap();
337
+ }
338
+
339
+ #[cfg(target_os = "linux")]
340
+ fn pid_fixture(mode: &str) -> (AgentCommand, PathBuf) {
341
+ use std::sync::atomic::{AtomicU64, Ordering};
342
+ static NEXT: AtomicU64 = AtomicU64::new(1);
343
+ let path = std::env::temp_dir().join(format!(
344
+ "ccht-native-pids-{}-{}.json",
345
+ std::process::id(),
346
+ NEXT.fetch_add(1, Ordering::Relaxed)
347
+ ));
348
+ let mut command = command(mode);
349
+ command.args.push(path.to_str().unwrap().into());
350
+ (command, path)
351
+ }
352
+
353
+ #[cfg(target_os = "linux")]
354
+ async fn fixture_pids(path: &std::path::Path) -> Vec<u32> {
355
+ timeout(Duration::from_secs(5), async {
356
+ loop {
357
+ if let Ok(bytes) = std::fs::read(path)
358
+ && let Ok(pids) = serde_json::from_slice::<BTreeMap<String, u32>>(&bytes)
359
+ {
360
+ return pids.into_values().collect();
361
+ }
362
+ tokio::time::sleep(Duration::from_millis(10)).await;
363
+ }
364
+ })
365
+ .await
366
+ .unwrap()
367
+ }
368
+
369
+ #[cfg(target_os = "linux")]
370
+ async fn assert_processes_stopped(pids: &[u32]) {
371
+ timeout(Duration::from_secs(5), async {
372
+ loop {
373
+ let running = pids.iter().any(|pid| {
374
+ std::fs::read_to_string(format!("/proc/{pid}/stat")).is_ok_and(|stat| {
375
+ // A zombie is terminated; reaping an orphan belongs to the
376
+ // worker's init process, not to the client under test.
377
+ !stat
378
+ .rsplit_once(") ")
379
+ .is_some_and(|(_, fields)| fields.starts_with('Z'))
380
+ })
381
+ });
382
+ if !running {
383
+ return;
384
+ }
385
+ tokio::time::sleep(Duration::from_millis(10)).await;
386
+ }
387
+ })
388
+ .await
389
+ .expect("SDK must terminate the agent and its descendant");
390
+ }
391
+
392
+ #[cfg(target_os = "linux")]
393
+ #[tokio::test]
394
+ async fn ignored_cancellation_really_terminates_the_sdk_process_group() {
395
+ let (launch, path) = pid_fixture("ignore_cancel");
396
+ let mut limits = options();
397
+ limits.shutdown_timeout = Duration::from_millis(100);
398
+ let client = NativeClient::connect(launch, limits).await.unwrap();
399
+ let pids = fixture_pids(&path).await;
400
+ let mut session = client
401
+ .new_session(SessionOptions::new(std::env::temp_dir()))
402
+ .await
403
+ .unwrap();
404
+ let handle = session.handle();
405
+ let mut events = session.take_events().unwrap();
406
+ let running = tokio::spawn({
407
+ let handle = handle.clone();
408
+ async move { handle.prompt(prompt("stop-processes")).await }
409
+ });
410
+ events.recv().await.unwrap();
411
+ assert_eq!(handle.cancel().await.unwrap_err(), NativeError::Timeout);
412
+ assert!(running.await.unwrap().is_err());
413
+ assert_processes_stopped(&pids).await;
414
+ let _ = std::fs::remove_file(path);
415
+ }
416
+
417
+ #[cfg(target_os = "linux")]
418
+ #[tokio::test]
419
+ async fn dropping_connect_during_initialization_really_terminates_its_children() {
420
+ let (launch, path) = pid_fixture("slow_init");
421
+ let connecting = tokio::spawn(NativeClient::connect(launch, options()));
422
+ let pids = fixture_pids(&path).await;
423
+ connecting.abort();
424
+ let _ = connecting.await;
425
+ assert_processes_stopped(&pids).await;
426
+ let _ = std::fs::remove_file(path);
427
+ }
428
+
429
+ #[tokio::test]
430
+ async fn advertised_controls_preserve_dependent_changes_and_reject_invalid_values() {
431
+ let (client, _session, handle, mut events) = session("normal", options()).await;
432
+ assert!(
433
+ handle
434
+ .configuration()
435
+ .accepts("model", &"test-model".into())
436
+ );
437
+ let changed = handle.set_model("second-model").await.unwrap();
438
+ assert!(matches!(&changed.options[1].kind,
439
+ crate::acp::SessionConfigKind::Boolean(value) if value.current_value));
440
+ let event = events.recv().await.unwrap();
441
+ assert!(event.request_id.is_none());
442
+ assert!(matches!(
443
+ event.event,
444
+ Event::Update {
445
+ update: SessionUpdate::ConfigOptionUpdate(_)
446
+ }
447
+ ));
448
+ assert!(
449
+ handle
450
+ .set_config_option("thinking", false.into())
451
+ .await
452
+ .is_ok()
453
+ );
454
+ assert!(matches!(
455
+ handle.set_model("not-offered").await,
456
+ Err(NativeError::Unsupported(_))
457
+ ));
458
+ assert!(matches!(
459
+ handle.set_config_option("thinking", "false".into()).await,
460
+ Err(NativeError::Unsupported(_))
461
+ ));
462
+ client.close().await.unwrap();
463
+ }
464
+
465
+ fn codex_fixture(mode: &str) -> super::drivers::CodexDeviceDriver {
466
+ use std::time::Duration;
467
+ super::drivers::CodexDeviceDriver::new("python3")
468
+ .with_lead_args(vec![
469
+ "-u".to_owned(),
470
+ "-c".to_owned(),
471
+ include_str!("fixture.py").to_owned(),
472
+ mode.to_owned(),
473
+ ])
474
+ .with_call_timeout(Duration::from_secs(5))
475
+ .with_approval_deadline(Duration::from_secs(5))
476
+ }
477
+
478
+ fn opencode_fixture(mode: &str, key: &str) -> super::drivers::OpenCodeKeyDriver {
479
+ use std::time::Duration;
480
+ super::drivers::OpenCodeKeyDriver::new("python3", key.to_owned())
481
+ .unwrap()
482
+ .with_lead_args(vec![
483
+ "-u".to_owned(),
484
+ "-c".to_owned(),
485
+ include_str!("fixture.py").to_owned(),
486
+ mode.to_owned(),
487
+ ])
488
+ .with_operation_timeout(Duration::from_secs(5))
489
+ .with_readiness_timeout(Duration::from_secs(5))
490
+ }
491
+
492
+ #[tokio::test]
493
+ async fn codex_challenge_round_trip_projects_presence() {
494
+ use super::drivers::{LoginDriver, LoginState};
495
+ let mut driver = codex_fixture("codex_ok");
496
+ let state = driver.start().await.unwrap();
497
+ let challenge = match state {
498
+ LoginState::ChallengeRequired(challenge) => challenge,
499
+ other => panic!("challenge expected, got {other:?}"),
500
+ };
501
+ assert_eq!(
502
+ challenge.verification_url,
503
+ "https://auth.openai.com/codex/device"
504
+ );
505
+ assert_eq!(challenge.user_code, "ABCD-1234");
506
+ challenge.validate().unwrap();
507
+ let state = driver.poll().await.unwrap();
508
+ match state {
509
+ LoginState::Authenticated(info) => {
510
+ assert_eq!(info.account.as_deref(), Some("user@example.com"));
511
+ }
512
+ other => panic!("authenticated presence expected, got {other:?}"),
513
+ }
514
+ let info = driver.account().await.unwrap();
515
+ assert_eq!(info.account.as_deref(), Some("user@example.com"));
516
+ }
517
+
518
+ #[tokio::test]
519
+ async fn codex_rejects_malformed_challenge_without_leak() {
520
+ use super::drivers::{Challenge, DriverError, LoginDriver};
521
+ for mode in ["codex_bad_url", "codex_bad_code"] {
522
+ let mut driver = codex_fixture(mode);
523
+ let error = driver.start().await.unwrap_err();
524
+ assert!(
525
+ matches!(error, DriverError::InvalidOptions(_)),
526
+ "expected invalid options for {mode}, got {error:?}"
527
+ );
528
+ assert_eq!(error.code(), "invalid_options");
529
+ let rendered = format!("{error} {error:?}");
530
+ assert!(!rendered.contains("ABCD-1234"));
531
+ assert!(!rendered.contains("evil.example.com"));
532
+ }
533
+ let bad = Challenge::new(
534
+ "http://evil.example.com/x".to_owned(),
535
+ "ABCD-1234".to_owned(),
536
+ );
537
+ assert!(matches!(
538
+ bad.validate().unwrap_err(),
539
+ DriverError::InvalidOptions(_)
540
+ ));
541
+ let short = Challenge::new(
542
+ "https://auth.openai.com/codex/device".to_owned(),
543
+ "x".to_owned(),
544
+ );
545
+ assert!(matches!(
546
+ short.validate().unwrap_err(),
547
+ DriverError::InvalidOptions(_)
548
+ ));
549
+ let custom = super::drivers::CodexDeviceDriver::with_allowed_hosts(
550
+ "python3",
551
+ vec!["example.com".to_owned()],
552
+ )
553
+ .unwrap()
554
+ .with_lead_args(vec![
555
+ "-u".to_owned(),
556
+ "-c".to_owned(),
557
+ include_str!("fixture.py").to_owned(),
558
+ "codex_ok".to_owned(),
559
+ ]);
560
+ let mut custom = custom;
561
+ let error = custom.start().await.unwrap_err();
562
+ assert_eq!(
563
+ error,
564
+ DriverError::InvalidOptions("challenge host is not allowed")
565
+ );
566
+ }
567
+
568
+ #[tokio::test]
569
+ async fn codex_poll_times_out_without_browser_approval() {
570
+ use super::drivers::{DriverError, LoginDriver, LoginState};
571
+ use std::time::Duration;
572
+ let mut driver = codex_fixture("codex_never");
573
+ driver = driver
574
+ .with_call_timeout(Duration::from_millis(300))
575
+ .with_approval_deadline(Duration::from_millis(400));
576
+ let state = driver.start().await.unwrap();
577
+ assert!(matches!(state, LoginState::ChallengeRequired(_)));
578
+ let error = driver.poll().await.unwrap_err();
579
+ assert_eq!(error, DriverError::Timeout);
580
+ assert_eq!(error.code(), "timeout");
581
+ }
582
+
583
+ #[tokio::test]
584
+ async fn codex_cancel_stops_helper_and_reports_cancelled() {
585
+ use super::drivers::{DriverError, LoginDriver, LoginState};
586
+ let mut driver = codex_fixture("codex_never");
587
+ let state = driver.start().await.unwrap();
588
+ assert!(matches!(state, LoginState::ChallengeRequired(_)));
589
+ assert!(driver.has_helper());
590
+ driver.cancel().await.unwrap();
591
+ assert!(!driver.has_helper());
592
+ assert_eq!(driver.poll().await.unwrap_err(), DriverError::Cancelled);
593
+ assert_eq!(driver.account().await.unwrap_err(), DriverError::Cancelled);
594
+ assert_eq!(driver.start().await.unwrap_err(), DriverError::Cancelled);
595
+ }
596
+
597
+ #[tokio::test]
598
+ async fn codex_declined_approval_reports_failed() {
599
+ use super::drivers::{LoginDriver, LoginState};
600
+ let mut driver = codex_fixture("codex_declined");
601
+ let state = driver.start().await.unwrap();
602
+ assert!(matches!(state, LoginState::ChallengeRequired(_)));
603
+ assert_eq!(driver.poll().await.unwrap(), LoginState::Failed);
604
+ }
605
+
606
+ #[tokio::test]
607
+ async fn opencode_key_login_confirms_connected() {
608
+ use super::drivers::{LoginDriver, LoginState};
609
+ let key = "ccht-fixture-key-9f8e7d6c5b4a";
610
+ let mut driver = opencode_fixture("opencode_ok", key);
611
+ let state = driver.start().await.unwrap();
612
+ match state {
613
+ LoginState::Authenticated(info) => {
614
+ assert_eq!(info.account.as_deref(), Some("opencode-go"));
615
+ }
616
+ other => panic!("authenticated presence expected, got {other:?}"),
617
+ }
618
+ let state = driver.poll().await.unwrap();
619
+ assert!(matches!(state, LoginState::Authenticated(_)));
620
+ let info = driver.account().await.unwrap();
621
+ assert_eq!(info.account.as_deref(), Some("opencode-go"));
622
+ let rendered = format!("{driver:?}");
623
+ assert!(!rendered.contains(key));
624
+ }
625
+
626
+ #[tokio::test]
627
+ async fn opencode_start_times_out_when_server_never_ready() {
628
+ use super::drivers::{DriverError, LoginDriver};
629
+ use std::time::Duration;
630
+ let mut driver = opencode_fixture("opencode_never", "ccht-fixture-key-timeout");
631
+ driver = driver
632
+ .with_operation_timeout(Duration::from_millis(300))
633
+ .with_readiness_timeout(Duration::from_millis(400));
634
+ let error = driver.start().await.unwrap_err();
635
+ assert_eq!(error, DriverError::Timeout);
636
+ }
637
+
638
+ #[tokio::test]
639
+ async fn driver_debug_and_errors_omit_key_material() {
640
+ use super::drivers::{DriverError, LoginDriver};
641
+ let key = "ccht-fixture-key-secret-12345";
642
+ let driver = super::drivers::OpenCodeKeyDriver::new("python3", key.to_owned()).unwrap();
643
+ let rendered = format!("{driver:?}");
644
+ assert!(!rendered.contains(key));
645
+ assert!(!rendered.contains("OPENCODE_SERVER_PASSWORD"));
646
+ let codex = super::drivers::CodexDeviceDriver::new("python3");
647
+ let codex_rendered = format!("{codex:?}");
648
+ assert!(!codex_rendered.contains("ABCD-1234"));
649
+ for error in [
650
+ DriverError::InvalidOptions("bad shape"),
651
+ DriverError::Timeout,
652
+ DriverError::Closed,
653
+ DriverError::Spawn("helper unavailable"),
654
+ DriverError::Protocol(-32603),
655
+ DriverError::Cancelled,
656
+ DriverError::Unsupported("extra step"),
657
+ ] {
658
+ let text = format!("{error} {error:?} {}", error.code());
659
+ assert!(!text.contains(key));
660
+ assert!(!text.contains("ccht-fixture"));
661
+ }
662
+ let mut failing = opencode_fixture("opencode_fail", key);
663
+ let state = failing.start().await.unwrap();
664
+ assert_eq!(state, super::drivers::LoginState::Failed);
665
+ let rendered = format!("{failing:?}");
666
+ assert!(!rendered.contains(key));
667
+ }