@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,62 @@
1
+ # Third-party components
2
+
3
+ ccht uses the official `agent-client-protocol` Rust SDK and
4
+ `agent-client-protocol-schema` under Apache-2.0. `wasm-bindgen` and the generated
5
+ binding toolchain retain their MIT/Apache-2.0 grants. The exact locked dependency
6
+ inventory is generated by `.ci/license_inventory.py`; browser distributions carry
7
+ original dependency notices in `LICENSES/dependencies/`.
8
+ No Zed editor source is included. Zed's external-agent architecture is a reference;
9
+ its GPL editor code is not relicensed by ccht's LGPL grant.
10
+
11
+ External runtimes are separately supplied by the operator:
12
+
13
+ | Runtime | Source license / terms |
14
+ | --- | --- |
15
+ | Codex ACP adapter and Codex | Apache-2.0; OpenAI account/service terms remain applicable |
16
+ | OpenCode | MIT; configured provider/account terms remain applicable |
17
+ | Claude ACP adapter | Apache-2.0 wrapper; the Claude Agent SDK/runtime has separate proprietary Anthropic terms |
18
+
19
+ ccht does not redistribute these executables. Preserve their original notices and
20
+ comply with their runtime and service conditions when packaging them yourself.
21
+ Do not infer permission to offer a customer-facing subscription login or pooled
22
+ account service from the wrapper's permissive license.
23
+
24
+ Permissive references informing the native login drivers (no vendored code;
25
+ hand-rolled protocol shapes with attribution in the module docs):
26
+
27
+ - Codex app-server protocol (`account/login/start` device-code challenge,
28
+ `account/login/completed`, `account/read`) from openai/codex under
29
+ Apache-2.0 informs `src/native/drivers/codex.rs` (`CodexDeviceDriver`).
30
+ The driver spawns the caller's Codex `app-server`, relays the
31
+ host-allowlisted challenge, and projects presence only.
32
+ - OpenCode `serve` control plane (`GET /global/health`,
33
+ `PUT /auth/opencode-go`, `GET /provider`) under MIT informs
34
+ `src/native/drivers/opencode.rs` (`OpenCodeKeyDriver`). The driver uses
35
+ loopback `opencode serve` with an ephemeral port, an env-only server
36
+ password, and hand-rolled HTTP with no new dependencies.
37
+
38
+ Preserve their original grants and notices when reusing these shapes.
39
+
40
+ Upstream sources: [ACP SDK](https://github.com/agentclientprotocol/rust-sdk),
41
+ [Codex ACP](https://github.com/agentclientprotocol/codex-acp),
42
+ [openai/codex](https://github.com/openai/codex),
43
+ [Claude ACP](https://github.com/agentclientprotocol/claude-agent-acp),
44
+ [OpenCode](https://github.com/anomalyco/opencode),
45
+ [wasm-bindgen](https://github.com/wasm-bindgen/wasm-bindgen).
46
+
47
+ The published ACP SDK and derive 2.1.0, ACP schema 1.7.0, defmt-parser 1.0.0,
48
+ wasm-encoder 0.245.1, and wasmparser 0.245.1 archives omit their repositories'
49
+ root license files. Their unchanged original notices are retained under
50
+ `.ci/upstream-notices/<package>-<version>/` for inclusion in browser artifacts.
51
+ This preserves Zed's copyright notices, both defmt license alternatives, and all
52
+ three wasm-tools license alternatives, including the LLVM exception.
53
+
54
+ The r-efi 6.0.0 archive already includes its full MIT grant, copyright notices,
55
+ and Apache-2.0/LGPL-2.1-or-later alternative notices in `AUTHORS`. That unchanged
56
+ file is also retained as a supplemental notice because its filename is outside
57
+ the usual `LICENSE`/`NOTICE` convention. All these notices were verified against
58
+ the exact upstream revisions recorded in the published crates'
59
+ `.cargo_vcs_info.json`; their crate archive checksums match `Cargo.lock`.
60
+ [Notice provenance](.ci/upstream-notices/PROVENANCE.json) records immutable source
61
+ URLs, revisions, upstream paths, Git blob hashes, and SHA-256 hashes. No upstream
62
+ implementation source or license alternatives were modified.
Binary file
@@ -0,0 +1,45 @@
1
+ //! Stream from an operator-supplied, already authenticated ACP executable.
2
+ //!
3
+ //! Example: cargo run --example native -- opencode acp
4
+
5
+ use ccht::native::{AgentCommand, NativeClient, NativeOptions, SessionOptions};
6
+ use ccht::{Event, Prompt, acp};
7
+
8
+ #[tokio::main]
9
+ async fn main() -> Result<(), Box<dyn std::error::Error>> {
10
+ let mut arguments = std::env::args().skip(1);
11
+ let executable = arguments
12
+ .next()
13
+ .ok_or("supply an installed ACP executable")?;
14
+ let directory = std::env::current_dir()?;
15
+ let command = AgentCommand::new(executable)
16
+ .args(arguments)
17
+ .with_working_directory(&directory)?;
18
+ let client = NativeClient::connect(command, NativeOptions::default()).await?;
19
+ let mut session = client.new_session(SessionOptions::new(directory)).await?;
20
+ let handle = session.handle();
21
+ let mut events = session.take_events()?;
22
+ let reader = tokio::spawn(async move {
23
+ while let Some(message) = events.recv().await {
24
+ match message.event {
25
+ Event::Update {
26
+ update: acp::SessionUpdate::AgentMessageChunk(chunk),
27
+ } => {
28
+ if let acp::ContentBlock::Text(text) = chunk.content {
29
+ print!("{}", text.text);
30
+ }
31
+ }
32
+ Event::Completed { .. } | Event::Error { .. } => break,
33
+ _ => {}
34
+ }
35
+ }
36
+ });
37
+ let result = handle
38
+ .prompt(Prompt::text("example-turn", "Say hello in one sentence."))
39
+ .await;
40
+ client.close().await?;
41
+ reader.await?;
42
+ result?;
43
+ println!();
44
+ Ok(())
45
+ }
@@ -0,0 +1,435 @@
1
+ //! Provider login state and credential-store abstraction.
2
+ //!
3
+ //! Structural inspiration comes from the provider/auth split in Zed
4
+ //! (GPL-3.0): uniform per-provider auth state, an application-supplied
5
+ //! credential store, and key lifecycle with environment override. This
6
+ //! module is reimplemented from scratch for LGPL use; no Zed code is
7
+ //! contained here.
8
+ //!
9
+ //! Boundary, unchanged: the store sees opaque bytes keyed by service URL
10
+ //! and never learns what they unlock; applications own login ceremonies,
11
+ //! UI, and where the store persists (OS keychain natively, browser storage
12
+ //! on the web). Nothing here performs network I/O.
13
+
14
+ use std::collections::HashMap;
15
+ use std::future::Future;
16
+ use std::pin::Pin;
17
+ use std::sync::Mutex;
18
+
19
+ use serde::{Deserialize, Serialize};
20
+
21
+ /// Login state of one provider as observed by the application.
22
+ #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
23
+ #[serde(rename_all = "snake_case")]
24
+ pub enum AuthState {
25
+ /// Not checked yet (for example, before the store was read).
26
+ #[default]
27
+ Unknown,
28
+ /// Credentials exist. The account label is display-only provenance and
29
+ /// must never be treated as an authentication proof by itself.
30
+ Authenticated {
31
+ /// Display-only account label (username, email, or subscription name).
32
+ account: Option<String>,
33
+ },
34
+ /// No credentials and no other evidence of a login.
35
+ Unauthenticated,
36
+ }
37
+
38
+ impl AuthState {
39
+ /// Whether routine work may proceed without prompting for login first.
40
+ #[must_use]
41
+ pub fn authenticated(&self) -> bool {
42
+ matches!(self, Self::Authenticated { .. })
43
+ }
44
+ }
45
+
46
+ /// Storage failure of a [`CredentialsProvider`].
47
+ #[derive(Clone, Debug, thiserror::Error, Eq, PartialEq)]
48
+ pub enum AuthError {
49
+ /// The backing store failed (keychain locked, disk full, quota hit).
50
+ #[error("credential store failed: {0}")]
51
+ Store(String),
52
+ /// The operation makes no sense for this store (for example, writing to
53
+ /// a read-only native-agent home owned by the agent itself).
54
+ #[error("operation not supported by this credential store")]
55
+ NotSupported,
56
+ }
57
+
58
+ /// Opaque credential: an account label plus secret bytes.
59
+ ///
60
+ /// Stores must treat both fields as opaque. The label exists so UIs can say
61
+ /// *who* is signed in without ever unlocking the secret.
62
+ #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
63
+ pub struct Credential {
64
+ /// Display-only account label (username, email, or subscription name).
65
+ pub account: String,
66
+ /// Secret bytes. Never logged, never embedded in errors or fixtures.
67
+ pub secret: Vec<u8>,
68
+ }
69
+
70
+ /// Application-supplied credential persistence.
71
+ ///
72
+ /// One method triple per service URL. Native applications back this with the
73
+ /// OS keychain; web applications with origin-scoped browser storage; tests
74
+ /// with [`MemoryCredentialsProvider`].
75
+ pub trait CredentialsProvider: Send + Sync {
76
+ /// Read stored credentials, if any, for a service URL.
77
+ fn read_credentials<'a>(
78
+ &'a self,
79
+ service: &'a str,
80
+ ) -> Pin<Box<dyn Future<Output = Result<Option<Credential>, AuthError>> + Send + 'a>>;
81
+
82
+ /// Persist credentials for a service URL, replacing any previous entry.
83
+ fn write_credentials<'a>(
84
+ &'a self,
85
+ service: &'a str,
86
+ credential: &'a Credential,
87
+ ) -> Pin<Box<dyn Future<Output = Result<(), AuthError>> + Send + 'a>>;
88
+
89
+ /// Remove stored credentials for a service URL. Missing entries are not
90
+ /// an error.
91
+ fn delete_credentials<'a>(
92
+ &'a self,
93
+ service: &'a str,
94
+ ) -> Pin<Box<dyn Future<Output = Result<(), AuthError>> + Send + 'a>>;
95
+ }
96
+
97
+ /// In-memory [`CredentialsProvider`] for tests and local development.
98
+ ///
99
+ /// Never ships credentials anywhere; drop it when the test ends.
100
+ #[derive(Debug, Default)]
101
+ pub struct MemoryCredentialsProvider {
102
+ entries: Mutex<HashMap<String, Credential>>,
103
+ }
104
+
105
+ impl MemoryCredentialsProvider {
106
+ /// Empty store.
107
+ #[must_use]
108
+ pub fn new() -> Self {
109
+ Self::default()
110
+ }
111
+ }
112
+
113
+ impl CredentialsProvider for MemoryCredentialsProvider {
114
+ fn read_credentials<'a>(
115
+ &'a self,
116
+ service: &'a str,
117
+ ) -> Pin<Box<dyn Future<Output = Result<Option<Credential>, AuthError>> + Send + 'a>> {
118
+ let found = match self.entries.lock() {
119
+ Ok(entries) => entries.get(service).cloned(),
120
+ Err(_) => {
121
+ return Box::pin(async move { Err(AuthError::Store("lock poisoned".into())) });
122
+ }
123
+ };
124
+ Box::pin(async move { Ok(found) })
125
+ }
126
+
127
+ fn write_credentials<'a>(
128
+ &'a self,
129
+ service: &'a str,
130
+ credential: &'a Credential,
131
+ ) -> Pin<Box<dyn Future<Output = Result<(), AuthError>> + Send + 'a>> {
132
+ let result = self
133
+ .entries
134
+ .lock()
135
+ .map(|mut entries| {
136
+ entries.insert(service.to_owned(), credential.clone());
137
+ })
138
+ .map_err(|_| AuthError::Store("lock poisoned".into()));
139
+ Box::pin(async move { result })
140
+ }
141
+
142
+ fn delete_credentials<'a>(
143
+ &'a self,
144
+ service: &'a str,
145
+ ) -> Pin<Box<dyn Future<Output = Result<(), AuthError>> + Send + 'a>> {
146
+ let result = self
147
+ .entries
148
+ .lock()
149
+ .map(|mut entries| {
150
+ entries.remove(service);
151
+ })
152
+ .map_err(|_| AuthError::Store("lock poisoned".into()));
153
+ Box::pin(async move { result })
154
+ }
155
+ }
156
+
157
+ /// Lifecycle of one provider's key: environment override wins, otherwise the
158
+ /// store decides. Mirrors the semantics applications need for a Zed-style
159
+ /// settings surface: `is_authenticated()` for badges, `store()` for the
160
+ /// save action, `reset()` for sign-out, `load_if_needed()` for lazy boot.
161
+ #[derive(Clone, Debug, Default)]
162
+ pub struct ApiKeyState {
163
+ key: Option<String>,
164
+ from_env_var: bool,
165
+ // The environment override is unavailable on Wasm; the field is still set
166
+ // through `new` on every target so construction stays uniform.
167
+ #[cfg_attr(target_family = "wasm", allow(dead_code))]
168
+ env_var_name: Option<&'static str>,
169
+ loaded_service: Option<String>,
170
+ }
171
+
172
+ impl ApiKeyState {
173
+ /// Unloaded state, optionally honoring an environment variable override.
174
+ #[must_use]
175
+ pub fn new(env_var_name: Option<&'static str>) -> Self {
176
+ Self {
177
+ env_var_name,
178
+ ..Self::default()
179
+ }
180
+ }
181
+
182
+ /// Whether routine work may proceed: an in-memory key is present.
183
+ #[must_use]
184
+ pub fn has_key(&self) -> bool {
185
+ self.key.as_deref().is_some_and(|key| !key.is_empty())
186
+ }
187
+
188
+ /// Whether the current key came from the environment (read-only: reset
189
+ /// is disabled and the UI must say so instead of failing silently).
190
+ #[must_use]
191
+ pub fn is_from_env_var(&self) -> bool {
192
+ self.from_env_var
193
+ }
194
+
195
+ /// The in-memory key, if any. Callers forward it to request signing;
196
+ /// they never persist or display it.
197
+ #[must_use]
198
+ pub fn key(&self) -> Option<&str> {
199
+ self.key.as_deref()
200
+ }
201
+
202
+ /// Load from environment or store unless this exact service already was.
203
+ /// Returns the resulting [`AuthState`].
204
+ ///
205
+ /// The environment override is unavailable on Wasm (browsers expose no
206
+ /// process environment); there the store alone decides.
207
+ pub async fn load_if_needed(
208
+ &mut self,
209
+ service: &str,
210
+ store: &(dyn CredentialsProvider + Send + Sync),
211
+ ) -> Result<AuthState, AuthError> {
212
+ if self.loaded_service.as_deref() == Some(service) {
213
+ return Ok(self.snapshot());
214
+ }
215
+ #[cfg(not(target_family = "wasm"))]
216
+ if let Some(name) = self.env_var_name
217
+ && let Ok(value) = std::env::var(name)
218
+ && !value.trim().is_empty()
219
+ {
220
+ self.key = Some(value);
221
+ self.from_env_var = true;
222
+ self.loaded_service = Some(service.to_owned());
223
+ return Ok(self.snapshot());
224
+ }
225
+ self.from_env_var = false;
226
+ self.key = store
227
+ .read_credentials(service)
228
+ .await?
229
+ .and_then(|credential| {
230
+ String::from_utf8(credential.secret)
231
+ .ok()
232
+ .filter(|secret| !secret.trim().is_empty())
233
+ });
234
+ self.loaded_service = Some(service.to_owned());
235
+ Ok(self.snapshot())
236
+ }
237
+
238
+ /// Forget a service change: the next `load_if_needed` reads again.
239
+ pub fn handle_service_change(&mut self, service: &str) {
240
+ if self.loaded_service.as_deref() != Some(service) {
241
+ self.key = None;
242
+ self.from_env_var = false;
243
+ self.loaded_service = None;
244
+ }
245
+ }
246
+
247
+ /// Persist a key (or `None` to sign out) through the store. Refuses while
248
+ /// the key comes from the environment: callers must unset the variable.
249
+ pub async fn store(
250
+ &mut self,
251
+ service: &str,
252
+ key: Option<String>,
253
+ store: &(dyn CredentialsProvider + Send + Sync),
254
+ ) -> Result<AuthState, AuthError> {
255
+ if self.from_env_var {
256
+ return Err(AuthError::NotSupported);
257
+ }
258
+ match key
259
+ .map(|key| key.trim().to_owned())
260
+ .filter(|key| !key.is_empty())
261
+ {
262
+ Some(key) => {
263
+ store
264
+ .write_credentials(
265
+ service,
266
+ &Credential {
267
+ account: String::new(),
268
+ secret: key.into_bytes(),
269
+ },
270
+ )
271
+ .await?;
272
+ self.key = store
273
+ .read_credentials(service)
274
+ .await?
275
+ .and_then(|credential| String::from_utf8(credential.secret).ok());
276
+ }
277
+ None => {
278
+ store.delete_credentials(service).await?;
279
+ self.key = None;
280
+ }
281
+ }
282
+ self.loaded_service = Some(service.to_owned());
283
+ Ok(self.snapshot())
284
+ }
285
+
286
+ fn snapshot(&self) -> AuthState {
287
+ if self.has_key() {
288
+ AuthState::Authenticated { account: None }
289
+ } else {
290
+ AuthState::Unauthenticated
291
+ }
292
+ }
293
+ }
294
+
295
+ #[cfg(test)]
296
+ mod tests {
297
+ use super::*;
298
+ use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
299
+
300
+ /// Minimal single-threaded executor so core tests need no async runtime.
301
+ fn block_on<F: Future>(mut future: F) -> F::Output {
302
+ // SAFETY: all waker callbacks ignore the null data pointer.
303
+ unsafe fn clone_raw(_: *const ()) -> RawWaker {
304
+ RawWaker::new(std::ptr::null(), &VTABLE)
305
+ }
306
+ unsafe fn noop_raw(_: *const ()) {}
307
+ static VTABLE: RawWakerVTable =
308
+ RawWakerVTable::new(clone_raw, noop_raw, noop_raw, noop_raw);
309
+ // SAFETY: the waker never dereferences its null data pointer.
310
+ let waker = unsafe { Waker::from_raw(RawWaker::new(std::ptr::null(), &VTABLE)) };
311
+ let mut context = Context::from_waker(&waker);
312
+ // SAFETY: the future is never moved after pinning for the poll loop.
313
+ let mut future = unsafe { Pin::new_unchecked(&mut future) };
314
+ loop {
315
+ match future.as_mut().poll(&mut context) {
316
+ Poll::Ready(output) => return output,
317
+ Poll::Pending => std::thread::yield_now(),
318
+ }
319
+ }
320
+ }
321
+
322
+ async fn roundtrip(store: &MemoryCredentialsProvider) {
323
+ let credential = Credential {
324
+ account: "Pro".into(),
325
+ secret: b"secret".to_vec(),
326
+ };
327
+ assert_eq!(store.read_credentials("svc").await.unwrap(), None);
328
+ store.write_credentials("svc", &credential).await.unwrap();
329
+ assert_eq!(
330
+ store.read_credentials("svc").await.unwrap(),
331
+ Some(credential)
332
+ );
333
+ store.delete_credentials("svc").await.unwrap();
334
+ assert_eq!(store.read_credentials("svc").await.unwrap(), None);
335
+ // Deleting a missing entry is not an error.
336
+ store.delete_credentials("svc").await.unwrap();
337
+ }
338
+
339
+ #[test]
340
+ fn memory_store_roundtrips() {
341
+ block_on(roundtrip(&MemoryCredentialsProvider::new()));
342
+ }
343
+
344
+ #[test]
345
+ fn api_key_state_starts_unauthenticated() {
346
+ let state = ApiKeyState::new(None);
347
+ assert!(!state.has_key());
348
+ assert!(!state.is_from_env_var());
349
+ assert_eq!(state.snapshot(), AuthState::Unauthenticated);
350
+ }
351
+
352
+ #[test]
353
+ fn api_key_state_save_and_sign_out() {
354
+ block_on(async {
355
+ let store = MemoryCredentialsProvider::new();
356
+ let mut state = ApiKeyState::new(None);
357
+ let seen = state.load_if_needed("svc", &store).await.unwrap();
358
+ assert_eq!(seen, AuthState::Unauthenticated);
359
+ let seen = state
360
+ .store("svc", Some(" key ".into()), &store)
361
+ .await
362
+ .unwrap();
363
+ assert_eq!(seen, AuthState::Authenticated { account: None });
364
+ assert!(state.has_key());
365
+ // Blank input signs out instead of storing whitespace.
366
+ let seen = state
367
+ .store("svc", Some(" ".into()), &store)
368
+ .await
369
+ .unwrap();
370
+ assert_eq!(seen, AuthState::Unauthenticated);
371
+ assert!(!state.has_key());
372
+ });
373
+ }
374
+
375
+ #[cfg(not(target_family = "wasm"))]
376
+ #[test]
377
+ fn api_key_state_prefers_environment_and_locks_reset() {
378
+ block_on(async {
379
+ // SAFETY: single-threaded test with no other environment readers.
380
+ unsafe { std::env::set_var("CCHT_TEST_API_KEY", "env-key") };
381
+ let store = MemoryCredentialsProvider::new();
382
+ let mut state = ApiKeyState::new(Some("CCHT_TEST_API_KEY"));
383
+ let seen = state.load_if_needed("svc", &store).await.unwrap();
384
+ assert_eq!(seen, AuthState::Authenticated { account: None });
385
+ assert!(state.is_from_env_var());
386
+ assert_eq!(
387
+ state.store("svc", None, &store).await.unwrap_err(),
388
+ AuthError::NotSupported
389
+ );
390
+ // SAFETY: restores the pre-test environment; see above.
391
+ unsafe { std::env::remove_var("CCHT_TEST_API_KEY") };
392
+ });
393
+ }
394
+
395
+ #[test]
396
+ fn api_key_state_reloads_on_service_change() {
397
+ block_on(async {
398
+ let store = MemoryCredentialsProvider::new();
399
+ let mut state = ApiKeyState::new(None);
400
+ state
401
+ .store("a", Some("key-a".into()), &store)
402
+ .await
403
+ .unwrap();
404
+ assert!(state.has_key());
405
+ state.handle_service_change("b");
406
+ assert!(!state.has_key());
407
+ let seen = state.load_if_needed("b", &store).await.unwrap();
408
+ assert_eq!(seen, AuthState::Unauthenticated);
409
+ });
410
+ }
411
+
412
+ #[test]
413
+ fn api_key_state_keeps_key_for_same_service() {
414
+ block_on(async {
415
+ let store = MemoryCredentialsProvider::new();
416
+ let mut state = ApiKeyState::new(None);
417
+ state
418
+ .store("a", Some("key-a".into()), &store)
419
+ .await
420
+ .unwrap();
421
+ state.handle_service_change("a");
422
+ assert!(state.has_key());
423
+ // A repeated load for the same service returns the cached snapshot.
424
+ let seen = state.load_if_needed("a", &store).await.unwrap();
425
+ assert_eq!(seen, AuthState::Authenticated { account: None });
426
+ });
427
+ }
428
+
429
+ #[test]
430
+ fn auth_state_reports_readiness() {
431
+ assert!(!AuthState::Unknown.authenticated());
432
+ assert!(!AuthState::Unauthenticated.authenticated());
433
+ assert!(AuthState::Authenticated { account: None }.authenticated());
434
+ }
435
+ }
@@ -0,0 +1,140 @@
1
+ //! Agent-owned session controls shared by native, Wasm and transport consumers.
2
+
3
+ use serde::{Deserialize, Serialize};
4
+
5
+ use crate::acp::{
6
+ SessionConfigKind, SessionConfigOption, SessionConfigOptionCategory, SessionConfigOptionValue,
7
+ SessionConfigSelectOptions, SessionModeState, SessionUpdate,
8
+ };
9
+
10
+ /// An agent's current advertised configuration; option order is significant.
11
+ #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
12
+ pub struct SessionConfiguration {
13
+ /// Model, mode, reasoning and other controls supplied by the agent.
14
+ pub options: Vec<SessionConfigOption>,
15
+ /// Legacy modes for agents that have not adopted configuration options.
16
+ pub modes: Option<SessionModeState>,
17
+ }
18
+
19
+ impl SessionConfiguration {
20
+ /// The first model selector, following the agent's priority ordering.
21
+ pub fn model_option(&self) -> Option<&SessionConfigOption> {
22
+ self.options.iter().find(|option| {
23
+ option.category == Some(SessionConfigOptionCategory::Model)
24
+ || option.id.0.as_ref() == "model"
25
+ })
26
+ }
27
+
28
+ /// Whether an exact value is offered, including grouped selectors and booleans.
29
+ pub fn accepts(&self, id: &str, value: &SessionConfigOptionValue) -> bool {
30
+ let Some(option) = self
31
+ .options
32
+ .iter()
33
+ .find(|option| option.id.0.as_ref() == id)
34
+ else {
35
+ return false;
36
+ };
37
+ match (&option.kind, value) {
38
+ (SessionConfigKind::Boolean(_), SessionConfigOptionValue::Boolean { .. }) => true,
39
+ (SessionConfigKind::Select(select), SessionConfigOptionValue::ValueId { value }) => {
40
+ match &select.options {
41
+ SessionConfigSelectOptions::Ungrouped(options) => {
42
+ options.iter().any(|option| option.value == *value)
43
+ }
44
+ SessionConfigSelectOptions::Grouped(groups) => groups
45
+ .iter()
46
+ .any(|group| group.options.iter().any(|option| option.value == *value)),
47
+ _ => false,
48
+ }
49
+ }
50
+ _ => false,
51
+ }
52
+ }
53
+
54
+ /// Apply an agent update. Configuration updates replace the complete option list.
55
+ pub fn apply(&mut self, update: &SessionUpdate) {
56
+ match update {
57
+ SessionUpdate::ConfigOptionUpdate(update) => {
58
+ self.options.clone_from(&update.config_options);
59
+ }
60
+ SessionUpdate::CurrentModeUpdate(update) => {
61
+ if let Some(modes) = &mut self.modes {
62
+ modes.current_mode_id.clone_from(&update.current_mode_id);
63
+ }
64
+ }
65
+ _ => {}
66
+ }
67
+ }
68
+ }
69
+
70
+ #[cfg(test)]
71
+ mod tests {
72
+ use super::*;
73
+ #[test]
74
+ fn grouped_selectors_and_boolean_controls_preserve_exact_types() {
75
+ let settings: SessionConfiguration = serde_json::from_value(serde_json::json!({
76
+ "options": [{"id":"model","name":"Model","category":"model","type":"select",
77
+ "currentValue":"one","options":[{"group":"provider","name":"Provider","options":[
78
+ {"value":"one","name":"One"},{"value":"two","name":"Two"}]}]},
79
+ {"id":"thinking","name":"Thinking","type":"boolean","currentValue":false}],
80
+ "modes":null
81
+ }))
82
+ .unwrap();
83
+ assert!(settings.accepts("model", &"two".into()));
84
+ assert!(!settings.accepts("model", &true.into()));
85
+ assert!(settings.accepts("thinking", &true.into()));
86
+ assert!(!settings.accepts("thinking", &"true".into()));
87
+ assert!(!settings.accepts("missing", &true.into()));
88
+ }
89
+
90
+ #[test]
91
+ fn model_option_is_none_without_advertised_model() {
92
+ assert!(SessionConfiguration::default().model_option().is_none());
93
+ }
94
+
95
+ #[test]
96
+ fn apply_replaces_options_and_tracks_current_mode() {
97
+ use crate::acp::{
98
+ ConfigOptionUpdate, ContentChunk, CurrentModeUpdate, SessionModeId, SessionModeState,
99
+ };
100
+ let mut settings = SessionConfiguration::default();
101
+ // Other updates leave the configuration unchanged.
102
+ settings.apply(&SessionUpdate::AgentMessageChunk(ContentChunk::new(
103
+ "hi".into(),
104
+ )));
105
+ assert!(settings.options.is_empty());
106
+
107
+ let options: SessionConfiguration = serde_json::from_value(serde_json::json!({
108
+ "options": [{"id":"model","name":"Model","type":"select",
109
+ "currentValue":"one","options":[{"value":"one","name":"One"}]}],
110
+ "modes": null
111
+ }))
112
+ .unwrap();
113
+ settings.apply(&SessionUpdate::ConfigOptionUpdate(ConfigOptionUpdate::new(
114
+ options.options.clone(),
115
+ )));
116
+ assert_eq!(settings.options, options.options);
117
+ assert!(settings.model_option().is_some());
118
+
119
+ // Without legacy modes, a mode update is a no-op.
120
+ settings.apply(&SessionUpdate::CurrentModeUpdate(CurrentModeUpdate::new(
121
+ SessionModeId::new("second"),
122
+ )));
123
+ assert!(settings.modes.is_none());
124
+
125
+ settings.modes = Some(SessionModeState::new(
126
+ SessionModeId::new("first"),
127
+ Vec::new(),
128
+ ));
129
+ settings.apply(&SessionUpdate::CurrentModeUpdate(CurrentModeUpdate::new(
130
+ SessionModeId::new("second"),
131
+ )));
132
+ assert_eq!(
133
+ settings
134
+ .modes
135
+ .as_ref()
136
+ .map(|modes| modes.current_mode_id.0.as_ref()),
137
+ Some("second")
138
+ );
139
+ }
140
+ }