@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,531 @@
1
+ //! API-key login through a native OpenCode control server.
2
+ //!
3
+ //! The driver starts `program serve` on loopback with an ephemeral port and
4
+ //! a random server password, stores the user key through the vendor auth
5
+ //! endpoint, and confirms presence through the vendor provider list. The
6
+ //! password lives only in the child environment; the user key lives only in
7
+ //! request bodies. Neither value appears in errors, logs, or debug output.
8
+
9
+ use std::path::PathBuf;
10
+ use std::process::Stdio;
11
+ use std::time::Duration;
12
+
13
+ use serde_json::Value;
14
+ use tokio::io::{AsyncReadExt, AsyncWriteExt};
15
+ use tokio::net::{TcpListener, TcpStream};
16
+ use tokio::process::{Child, Command};
17
+ use tokio::time::{Instant, sleep, timeout};
18
+
19
+ use super::{AccountInfo, DriverError, LoginDriver, LoginState};
20
+
21
+ /// Upper bound for one control-plane reply body.
22
+ const MAX_BODY: usize = 1_048_576;
23
+
24
+ /// Vendor provider id reported as the display label on success.
25
+ const PROVIDER_ID: &str = "opencode-go";
26
+
27
+ /// Key login against an ephemeral OpenCode control server.
28
+ ///
29
+ /// The server password is random per attempt and passed only through the
30
+ /// child environment. The user key is supplied by the application and sent
31
+ /// only in the vendor `PUT` body. The child is stopped on drop and on
32
+ /// cancellation.
33
+ pub struct OpenCodeKeyDriver {
34
+ program: PathBuf,
35
+ lead_args: Vec<String>,
36
+ api_key: String,
37
+ operation_timeout: Duration,
38
+ readiness_timeout: Duration,
39
+ helper: Option<RunningHelper>,
40
+ cancelled: bool,
41
+ }
42
+
43
+ /// Running control server for one attempt.
44
+ struct RunningHelper {
45
+ child: Child,
46
+ port: u16,
47
+ password: String,
48
+ }
49
+
50
+ impl OpenCodeKeyDriver {
51
+ /// Create a driver for one user-supplied key.
52
+ ///
53
+ /// The program is the OpenCode executable; `serve --hostname 127.0.0.1
54
+ /// --port <ephemeral>` is appended at spawn time. Fixture tests prepend
55
+ /// interpreter arguments with [`OpenCodeKeyDriver::with_lead_args`].
56
+ ///
57
+ /// # Errors
58
+ ///
59
+ /// Returns [`DriverError::InvalidOptions`] when the program or the key
60
+ /// is empty.
61
+ pub fn new(program: impl Into<PathBuf>, api_key: String) -> Result<Self, DriverError> {
62
+ let program = program.into();
63
+ if program.as_os_str().is_empty() {
64
+ return Err(DriverError::InvalidOptions(
65
+ "opencode program must not be empty",
66
+ ));
67
+ }
68
+ if api_key.trim().is_empty() {
69
+ return Err(DriverError::InvalidOptions(
70
+ "opencode key must not be empty",
71
+ ));
72
+ }
73
+ Ok(Self {
74
+ program,
75
+ lead_args: Vec::new(),
76
+ api_key,
77
+ operation_timeout: Duration::from_secs(10),
78
+ readiness_timeout: Duration::from_secs(15),
79
+ helper: None,
80
+ cancelled: false,
81
+ })
82
+ }
83
+
84
+ /// Prepend arguments before the appended `serve` token.
85
+ ///
86
+ /// Production use leaves this empty; fixture tests pass an interpreter
87
+ /// preamble such as `-u -c <code> <mode>` here.
88
+ pub fn with_lead_args(mut self, args: Vec<String>) -> Self {
89
+ self.lead_args = args;
90
+ self
91
+ }
92
+
93
+ /// Set the deadline for one HTTP round trip.
94
+ pub fn with_operation_timeout(mut self, limit: Duration) -> Self {
95
+ self.operation_timeout = limit;
96
+ self
97
+ }
98
+
99
+ /// Set how long `start` waits for `/global/health` to succeed.
100
+ pub fn with_readiness_timeout(mut self, limit: Duration) -> Self {
101
+ self.readiness_timeout = limit;
102
+ self
103
+ }
104
+
105
+ /// Whether a control server is currently running.
106
+ pub fn has_helper(&self) -> bool {
107
+ self.helper.is_some()
108
+ }
109
+
110
+ /// Stop the helper without exposing secrets.
111
+ fn shutdown(&mut self) {
112
+ if let Some(mut live) = self.helper.take() {
113
+ let _ = live.child.start_kill();
114
+ }
115
+ }
116
+ }
117
+
118
+ impl std::fmt::Debug for OpenCodeKeyDriver {
119
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120
+ f.debug_struct("OpenCodeKeyDriver")
121
+ .field(
122
+ "phase",
123
+ if self.cancelled {
124
+ &"cancelled"
125
+ } else if self.helper.is_some() {
126
+ &"running"
127
+ } else {
128
+ &"idle"
129
+ },
130
+ )
131
+ .field("has_helper", &self.helper.is_some())
132
+ .finish()
133
+ }
134
+ }
135
+
136
+ impl Drop for OpenCodeKeyDriver {
137
+ fn drop(&mut self) {
138
+ self.shutdown();
139
+ }
140
+ }
141
+
142
+ /// Standard base64 alphabet for basic authentication.
143
+ const B64_TABLE: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
144
+
145
+ /// Encode bytes as base64 without external crates.
146
+ fn base64_encode(input: &[u8]) -> String {
147
+ let mut out = String::with_capacity(input.len().div_ceil(3) * 4);
148
+ for chunk in input.chunks(3) {
149
+ let mut block: u32 = 0;
150
+ for (slot, byte) in chunk.iter().enumerate() {
151
+ block |= (*byte as u32) << (16 - 8 * slot);
152
+ }
153
+ let pad = 3 - chunk.len();
154
+ for slot in 0..4 - pad {
155
+ let sextet = ((block >> (18 - 6 * slot)) & 0x3F) as usize;
156
+ out.push(B64_TABLE[sextet] as char);
157
+ }
158
+ for _ in 0..pad {
159
+ out.push('=');
160
+ }
161
+ }
162
+ out
163
+ }
164
+
165
+ /// Basic header value for the fixed `opencode` user.
166
+ fn auth_value(password: &str) -> String {
167
+ base64_encode(format!("opencode:{password}").as_bytes())
168
+ }
169
+
170
+ /// Random ephemeral password without new dependencies.
171
+ ///
172
+ /// Prefers operating-system randomness; falls back to a time-seeded mix so
173
+ /// tests on constrained hosts still get a unique value per attempt.
174
+ fn ephemeral_password() -> String {
175
+ let mut raw = [0u8; 24];
176
+ let mut filled = false;
177
+ if let Ok(mut source) = std::fs::File::open("/dev/urandom") {
178
+ use std::io::Read as _;
179
+ if source.read_exact(&mut raw).is_ok() {
180
+ filled = true;
181
+ }
182
+ }
183
+ if !filled {
184
+ let nanos = std::time::SystemTime::now()
185
+ .duration_since(std::time::UNIX_EPOCH)
186
+ .map(|span| span.as_nanos())
187
+ .unwrap_or(0);
188
+ let pid = std::process::id() as u128;
189
+ let mut mix = nanos ^ ((pid << 64) | 0x9e37_79b9_7f4a_7c15);
190
+ for slot in raw.iter_mut() {
191
+ mix ^= mix >> 29;
192
+ mix = mix.wrapping_mul(0xbf58_476d_1ce4_e5b9);
193
+ mix ^= mix >> 32;
194
+ *slot = (mix & 0xFF) as u8;
195
+ }
196
+ }
197
+ let mut text = String::with_capacity(raw.len() * 2);
198
+ for byte in raw {
199
+ text.push(char::from_digit((byte >> 4) as u32, 16).unwrap_or('0'));
200
+ text.push(char::from_digit((byte & 0x0F) as u32, 16).unwrap_or('0'));
201
+ }
202
+ text
203
+ }
204
+
205
+ /// Claim an ephemeral loopback port by binding, then release it.
206
+ async fn free_port(limit: Duration) -> Result<u16, DriverError> {
207
+ let listener = timeout(limit, TcpListener::bind("127.0.0.1:0"))
208
+ .await
209
+ .map_err(|_| DriverError::Timeout)?
210
+ .map_err(|_| DriverError::Spawn("control port was unavailable"))?;
211
+ let port = listener
212
+ .local_addr()
213
+ .map_err(|_| DriverError::Spawn("control port was unavailable"))?
214
+ .port();
215
+ drop(listener);
216
+ if port == 0 {
217
+ return Err(DriverError::Spawn("control port was unavailable"));
218
+ }
219
+ Ok(port)
220
+ }
221
+
222
+ /// Spawn the control server with a cleared minimal environment.
223
+ fn launch(
224
+ program: &PathBuf,
225
+ lead: &[String],
226
+ port: u16,
227
+ password: &str,
228
+ ) -> Result<Child, DriverError> {
229
+ if program.as_os_str().is_empty() {
230
+ return Err(DriverError::InvalidOptions(
231
+ "opencode program must not be empty",
232
+ ));
233
+ }
234
+ let home = std::env::var("HOME")
235
+ .unwrap_or_else(|_| std::env::temp_dir().to_string_lossy().into_owned());
236
+ // Resolve bare names against the parent PATH before clearing it, so
237
+ // fixtures work where the interpreter lives outside the minimal set.
238
+ let resolved = super::resolve_program(program);
239
+ let mut spawn = Command::new(&resolved);
240
+ spawn
241
+ .args(lead)
242
+ .args([
243
+ "serve",
244
+ "--hostname",
245
+ "127.0.0.1",
246
+ "--port",
247
+ &port.to_string(),
248
+ ])
249
+ .env_clear()
250
+ .env("PATH", "/usr/local/bin:/usr/bin:/bin")
251
+ .env("HOME", home)
252
+ .env("OPENCODE_SERVER_PASSWORD", password)
253
+ .stdin(Stdio::null())
254
+ .stdout(Stdio::null())
255
+ .stderr(Stdio::null())
256
+ .kill_on_drop(true);
257
+ spawn
258
+ .spawn()
259
+ .map_err(|_| DriverError::Spawn("control server could not be launched"))
260
+ }
261
+
262
+ /// One hand-rolled HTTP round trip over loopback.
263
+ ///
264
+ /// Uses `Connection: close` so the reply ends at EOF; the body is capped.
265
+ async fn http_call(
266
+ method: &str,
267
+ path: &str,
268
+ port: u16,
269
+ password: &str,
270
+ body: Option<&[u8]>,
271
+ limit: Duration,
272
+ ) -> Result<(u16, Vec<u8>), DriverError> {
273
+ let mut stream = timeout(limit, TcpStream::connect(("127.0.0.1", port)))
274
+ .await
275
+ .map_err(|_| DriverError::Timeout)?
276
+ .map_err(|_| DriverError::Closed)?;
277
+ let auth = auth_value(password);
278
+ let length = body.map_or(0, <[u8]>::len);
279
+ let head = format!(
280
+ "{method} {path} HTTP/1.1\r\nHost: 127.0.0.1:{port}\r\nAuthorization: Basic {auth}\r\nContent-Type: application/json\r\nContent-Length: {length}\r\nConnection: close\r\n\r\n"
281
+ );
282
+ timeout(limit, stream.write_all(head.as_bytes()))
283
+ .await
284
+ .map_err(|_| DriverError::Timeout)?
285
+ .map_err(|_| DriverError::Closed)?;
286
+ if let Some(payload) = body {
287
+ timeout(limit, stream.write_all(payload))
288
+ .await
289
+ .map_err(|_| DriverError::Timeout)?
290
+ .map_err(|_| DriverError::Closed)?;
291
+ }
292
+ timeout(limit, stream.flush())
293
+ .await
294
+ .map_err(|_| DriverError::Timeout)?
295
+ .map_err(|_| DriverError::Closed)?;
296
+ let mut raw = Vec::new();
297
+ let mut chunk = [0u8; 8_192];
298
+ let outcome: Result<(), DriverError> = timeout(limit, async {
299
+ loop {
300
+ match stream.read(&mut chunk).await {
301
+ Ok(0) => return Ok(()),
302
+ Ok(count) => {
303
+ if raw.len() + count > MAX_BODY + 8_192 {
304
+ return Err(DriverError::Protocol(-32700));
305
+ }
306
+ raw.extend_from_slice(&chunk[..count]);
307
+ }
308
+ Err(_) => return Err(DriverError::Closed),
309
+ }
310
+ }
311
+ })
312
+ .await
313
+ .map_err(|_| DriverError::Timeout)?;
314
+ outcome?;
315
+ if raw.len() > MAX_BODY + 8_192 {
316
+ return Err(DriverError::Protocol(-32700));
317
+ }
318
+ let text = String::from_utf8_lossy(&raw);
319
+ let (head, body) = text.split_once("\r\n\r\n").unwrap_or((&text, ""));
320
+ let status_line = head.lines().next().unwrap_or_default();
321
+ let mut parts = status_line.split_whitespace();
322
+ let _version = parts.next();
323
+ let code_text = parts.next().unwrap_or_default();
324
+ let code: u16 = code_text
325
+ .parse()
326
+ .map_err(|_| DriverError::Protocol(-32700))?;
327
+ let mut payload = body.as_bytes().to_vec();
328
+ if payload.len() > MAX_BODY {
329
+ return Err(DriverError::Protocol(-32700));
330
+ }
331
+ // Prefer Content-Length when the server keeps framing exact.
332
+ if let Some(wanted) = head
333
+ .lines()
334
+ .find_map(|line| line.strip_prefix("Content-Length:"))
335
+ .and_then(|value| value.trim().parse::<usize>().ok())
336
+ && wanted <= MAX_BODY
337
+ {
338
+ payload.truncate(wanted.min(payload.len()));
339
+ }
340
+ Ok((code, payload))
341
+ }
342
+
343
+ /// Wait until `/global/health` answers 2xx or the helper exits.
344
+ async fn await_ready(helper: &mut RunningHelper, limit: Duration) -> Result<(), DriverError> {
345
+ if limit.is_zero() {
346
+ return Err(DriverError::InvalidOptions(
347
+ "driver deadlines must be positive",
348
+ ));
349
+ }
350
+ let start = Instant::now();
351
+ loop {
352
+ if start.elapsed() >= limit {
353
+ return Err(DriverError::Timeout);
354
+ }
355
+ match helper.child.try_wait() {
356
+ Ok(Some(_)) => {
357
+ return Err(DriverError::Spawn(
358
+ "control server stopped before readiness",
359
+ ));
360
+ }
361
+ Ok(None) => {}
362
+ Err(_) => {
363
+ return Err(DriverError::Spawn(
364
+ "control server stopped before readiness",
365
+ ));
366
+ }
367
+ }
368
+ let attempt = (limit - start.elapsed()).min(Duration::from_secs(2));
369
+ match http_call(
370
+ "GET",
371
+ "/global/health",
372
+ helper.port,
373
+ &helper.password,
374
+ None,
375
+ attempt,
376
+ )
377
+ .await
378
+ {
379
+ Ok((code, _)) if (200..300).contains(&code) => return Ok(()),
380
+ Ok(_) => {}
381
+ Err(DriverError::Closed) => {}
382
+ Err(DriverError::Timeout) => {}
383
+ Err(other) => return Err(other),
384
+ }
385
+ sleep(Duration::from_millis(50)).await;
386
+ }
387
+ }
388
+
389
+ /// Whether the provider reply lists the expected vendor id.
390
+ fn is_connected(reply: &[u8]) -> Result<bool, DriverError> {
391
+ let value: Value = serde_json::from_slice(reply).map_err(|_| DriverError::Protocol(-32700))?;
392
+ let listed = value
393
+ .get("connected")
394
+ .and_then(Value::as_array)
395
+ .ok_or(DriverError::Protocol(-32603))?;
396
+ Ok(listed
397
+ .iter()
398
+ .any(|entry| entry.as_str() == Some(PROVIDER_ID)))
399
+ }
400
+
401
+ impl LoginDriver for OpenCodeKeyDriver {
402
+ /// Start the server, store the key, and confirm presence.
403
+ async fn start(&mut self) -> Result<LoginState, DriverError> {
404
+ if self.cancelled {
405
+ return Err(DriverError::Cancelled);
406
+ }
407
+ self.shutdown();
408
+ if self.operation_timeout.is_zero() || self.readiness_timeout.is_zero() {
409
+ return Err(DriverError::InvalidOptions(
410
+ "driver deadlines must be positive",
411
+ ));
412
+ }
413
+ let port = free_port(self.operation_timeout).await?;
414
+ let password = ephemeral_password();
415
+ let child = launch(&self.program, &self.lead_args, port, &password)?;
416
+ let mut live = RunningHelper {
417
+ child,
418
+ port,
419
+ password,
420
+ };
421
+ await_ready(&mut live, self.readiness_timeout)
422
+ .await
423
+ .inspect_err(|_| {
424
+ let _ = live.child.start_kill();
425
+ })?;
426
+ let payload = serde_json::json!({"type": "api", "key": self.api_key.clone()});
427
+ let bytes = serde_json::to_vec(&payload).map_err(|_| DriverError::Protocol(-32700))?;
428
+ let (stored, _) = http_call(
429
+ "PUT",
430
+ "/auth/opencode-go",
431
+ live.port,
432
+ &live.password,
433
+ Some(&bytes),
434
+ self.operation_timeout,
435
+ )
436
+ .await
437
+ .inspect_err(|_| {
438
+ let _ = live.child.start_kill();
439
+ })?;
440
+ if !(200..300).contains(&stored) {
441
+ let _ = live.child.start_kill();
442
+ return Ok(LoginState::Failed);
443
+ }
444
+ let (code, reply) = http_call(
445
+ "GET",
446
+ "/provider",
447
+ live.port,
448
+ &live.password,
449
+ None,
450
+ self.operation_timeout,
451
+ )
452
+ .await
453
+ .inspect_err(|_| {
454
+ let _ = live.child.start_kill();
455
+ })?;
456
+ if !(200..300).contains(&code) {
457
+ let _ = live.child.start_kill();
458
+ return Err(DriverError::Protocol(code as i32));
459
+ }
460
+ let connected = is_connected(&reply).inspect_err(|_| {
461
+ let _ = live.child.start_kill();
462
+ })?;
463
+ if !connected {
464
+ let _ = live.child.start_kill();
465
+ return Ok(LoginState::Failed);
466
+ }
467
+ self.helper = Some(live);
468
+ Ok(LoginState::Authenticated(AccountInfo::new(Some(
469
+ PROVIDER_ID.to_owned(),
470
+ ))))
471
+ }
472
+
473
+ /// Re-read provider presence on the running server.
474
+ async fn poll(&mut self) -> Result<LoginState, DriverError> {
475
+ if self.cancelled {
476
+ return Err(DriverError::Cancelled);
477
+ }
478
+ let live = self.helper.as_mut().ok_or(DriverError::Closed)?;
479
+ let (code, reply) = http_call(
480
+ "GET",
481
+ "/provider",
482
+ live.port,
483
+ &live.password,
484
+ None,
485
+ self.operation_timeout,
486
+ )
487
+ .await?;
488
+ if !(200..300).contains(&code) {
489
+ return Err(DriverError::Protocol(code as i32));
490
+ }
491
+ if is_connected(&reply)? {
492
+ Ok(LoginState::Authenticated(AccountInfo::new(Some(
493
+ PROVIDER_ID.to_owned(),
494
+ ))))
495
+ } else {
496
+ Ok(LoginState::Failed)
497
+ }
498
+ }
499
+
500
+ /// Re-read provider presence as display-only state.
501
+ async fn account(&mut self) -> Result<AccountInfo, DriverError> {
502
+ if self.cancelled {
503
+ return Err(DriverError::Cancelled);
504
+ }
505
+ let live = self.helper.as_mut().ok_or(DriverError::Closed)?;
506
+ let (code, reply) = http_call(
507
+ "GET",
508
+ "/provider",
509
+ live.port,
510
+ &live.password,
511
+ None,
512
+ self.operation_timeout,
513
+ )
514
+ .await?;
515
+ if !(200..300).contains(&code) {
516
+ return Err(DriverError::Protocol(code as i32));
517
+ }
518
+ if is_connected(&reply)? {
519
+ Ok(AccountInfo::new(Some(PROVIDER_ID.to_owned())))
520
+ } else {
521
+ Ok(AccountInfo::signed_out())
522
+ }
523
+ }
524
+
525
+ /// Stop the server; later steps report cancellation.
526
+ async fn cancel(&mut self) -> Result<(), DriverError> {
527
+ self.cancelled = true;
528
+ self.shutdown();
529
+ Ok(())
530
+ }
531
+ }