chutils 3.6.0__tar.gz → 3.7.0__tar.gz

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 (759) hide show
  1. {chutils-3.6.0 → chutils-3.7.0}/.github/workflows/ci.yml +46 -46
  2. {chutils-3.6.0 → chutils-3.7.0}/PKG-INFO +5 -1
  3. {chutils-3.6.0 → chutils-3.7.0}/ai-lint.toml +2 -0
  4. {chutils-3.6.0 → chutils-3.7.0}/api_map.md +19 -12
  5. {chutils-3.6.0 → chutils-3.7.0}/benchmarks/cold_start.py +2 -2
  6. chutils-3.7.0/conductor/archive/advanced_antidetect_e2e_20260910/index.md +5 -0
  7. chutils-3.7.0/conductor/archive/advanced_antidetect_e2e_20260910/index.md.metadata.json +4 -0
  8. chutils-3.7.0/conductor/archive/advanced_antidetect_e2e_20260910/metadata.json +8 -0
  9. chutils-3.7.0/conductor/archive/advanced_antidetect_e2e_20260910/plan.md +29 -0
  10. chutils-3.7.0/conductor/archive/advanced_antidetect_e2e_20260910/plan.md.metadata.json +4 -0
  11. chutils-3.7.0/conductor/archive/advanced_antidetect_e2e_20260910/spec.md +25 -0
  12. chutils-3.7.0/conductor/archive/advanced_antidetect_e2e_20260910/spec.md.metadata.json +4 -0
  13. chutils-3.7.0/conductor/archive/nodriver_antidetect_20260910/index.md +5 -0
  14. chutils-3.7.0/conductor/archive/nodriver_antidetect_20260910/metadata.json +8 -0
  15. chutils-3.7.0/conductor/archive/nodriver_antidetect_20260910/plan.md +41 -0
  16. chutils-3.7.0/conductor/archive/nodriver_antidetect_20260910/spec.md +31 -0
  17. chutils-3.7.0/conductor/archive/nodriver_launch_turnstile_fix_20260910/index.md +5 -0
  18. chutils-3.7.0/conductor/archive/nodriver_launch_turnstile_fix_20260910/metadata.json +9 -0
  19. chutils-3.7.0/conductor/archive/nodriver_launch_turnstile_fix_20260910/plan.md +39 -0
  20. chutils-3.7.0/conductor/archive/nodriver_launch_turnstile_fix_20260910/spec.md +34 -0
  21. chutils-3.7.0/conductor/archive/nodriver_stealth_turnstile_20260910/index.md +5 -0
  22. chutils-3.7.0/conductor/archive/nodriver_stealth_turnstile_20260910/metadata.json +8 -0
  23. chutils-3.7.0/conductor/archive/nodriver_stealth_turnstile_20260910/plan.md +38 -0
  24. chutils-3.7.0/conductor/archive/nodriver_stealth_turnstile_20260910/spec.md +53 -0
  25. chutils-3.7.0/conductor/archive/profile_warmer_20260910/index.md +5 -0
  26. chutils-3.7.0/conductor/archive/profile_warmer_20260910/metadata.json +8 -0
  27. chutils-3.7.0/conductor/archive/profile_warmer_20260910/plan.md +38 -0
  28. chutils-3.7.0/conductor/archive/profile_warmer_20260910/spec.md +33 -0
  29. chutils-3.7.0/conductor/archive/proxy_manager_20260910/index.md +5 -0
  30. chutils-3.7.0/conductor/archive/proxy_manager_20260910/metadata.json +8 -0
  31. chutils-3.7.0/conductor/archive/proxy_manager_20260910/plan.md +39 -0
  32. chutils-3.7.0/conductor/archive/proxy_manager_20260910/spec.md +42 -0
  33. chutils-3.7.0/conductor/archive/scraping_testing_20260910/index.md +5 -0
  34. chutils-3.7.0/conductor/archive/scraping_testing_20260910/metadata.json +8 -0
  35. chutils-3.7.0/conductor/archive/scraping_testing_20260910/plan.md +50 -0
  36. chutils-3.7.0/conductor/archive/scraping_testing_20260910/spec.md +48 -0
  37. chutils-3.7.0/conductor/archive/tls_impersonation_antidetect_20260910/index.md +5 -0
  38. chutils-3.7.0/conductor/archive/tls_impersonation_antidetect_20260910/metadata.json +8 -0
  39. chutils-3.7.0/conductor/archive/tls_impersonation_antidetect_20260910/plan.md +40 -0
  40. chutils-3.7.0/conductor/archive/tls_impersonation_antidetect_20260910/spec.md +36 -0
  41. {chutils-3.6.0 → chutils-3.7.0}/conductor/product.md +24 -0
  42. {chutils-3.6.0 → chutils-3.7.0}/conductor/tech-stack.md +2 -0
  43. chutils-3.7.0/conductor/tracks/nextgen_antidetect_bidi_20260915/index.md +5 -0
  44. chutils-3.7.0/conductor/tracks/nextgen_antidetect_bidi_20260915/metadata.json +8 -0
  45. chutils-3.7.0/conductor/tracks/nextgen_antidetect_bidi_20260915/plan.md +50 -0
  46. chutils-3.7.0/conductor/tracks/nextgen_antidetect_bidi_20260915/spec.md +59 -0
  47. chutils-3.7.0/conductor/tracks.md +39 -0
  48. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_examples/configuration/bad_pattern.py +22 -22
  49. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_examples/error_handling/good_pattern.py +92 -92
  50. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_examples/logging/bad_pattern.py +27 -27
  51. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_examples/logging/good_pattern.py +38 -38
  52. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_examples/optional_deps/bad_pattern.py +48 -48
  53. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_examples/optional_deps/good_pattern.py +68 -68
  54. {chutils-3.6.0 → chutils-3.7.0}/docs/api.md +43 -1
  55. {chutils-3.6.0 → chutils-3.7.0}/docs/dependencies.md +4 -2
  56. chutils-3.7.0/docs/http.md +221 -0
  57. {chutils-3.6.0 → chutils-3.7.0}/docs/migration.md +238 -238
  58. chutils-3.7.0/docs/scraping.md +1064 -0
  59. {chutils-3.6.0 → chutils-3.7.0}/examples/01_configuration.py +50 -50
  60. {chutils-3.6.0 → chutils-3.7.0}/examples/06_local_config_override.py +81 -81
  61. {chutils-3.6.0 → chutils-3.7.0}/examples/08_multiple_loggers_example.py +40 -40
  62. {chutils-3.6.0 → chutils-3.7.0}/examples/22_safe_path_resolution.py +91 -91
  63. {chutils-3.6.0 → chutils-3.7.0}/examples/26_metrics_prometheus.py +1 -1
  64. {chutils-3.6.0 → chutils-3.7.0}/examples/captcha_solvers_usage.py +67 -67
  65. {chutils-3.6.0 → chutils-3.7.0}/examples/scraping_humanize_usage.py +69 -69
  66. {chutils-3.6.0 → chutils-3.7.0}/project_index.json +6137 -227
  67. {chutils-3.6.0 → chutils-3.7.0}/pyproject.toml +196 -170
  68. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/__init__.py +448 -438
  69. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/cli_utils.py +2 -1
  70. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/pypi.py +5 -4
  71. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/core.py +1 -3
  72. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/manager.py +411 -411
  73. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/paths.py +212 -212
  74. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/tracing.py +125 -125
  75. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/few_shot/detector.py +3 -1
  76. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/few_shot/writer.py +3 -1
  77. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/rules/docstring.py +8 -8
  78. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/rules/security.py +133 -133
  79. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/env.py +1 -1
  80. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/events/__init__.py +0 -1
  81. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/events/core.py +0 -1
  82. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/http/__init__.py +77 -63
  83. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/http/async_client.py +333 -335
  84. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/http/client.py +10 -10
  85. chutils-3.7.0/src/chutils/http/tls_client.py +558 -0
  86. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/lifecycle.py +26 -0
  87. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/logger/handlers.py +6 -1
  88. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/logger/internal/builder.py +4 -1
  89. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/qt/shim.py +2 -1
  90. chutils-3.7.0/src/chutils/scraping/__init__.py +213 -0
  91. chutils-3.7.0/src/chutils/scraping/camoufox.py +61 -0
  92. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/captcha/exceptions.py +17 -17
  93. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/humanize/__init__.py +71 -48
  94. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/humanize/actions.py +23 -3
  95. chutils-3.7.0/src/chutils/scraping/humanize/antidetect.py +421 -0
  96. chutils-3.7.0/src/chutils/scraping/humanize/antidetect_scripts.py +464 -0
  97. chutils-3.7.0/src/chutils/scraping/humanize/config.py +179 -0
  98. chutils-3.7.0/src/chutils/scraping/humanize/search.py +176 -0
  99. chutils-3.7.0/src/chutils/scraping/humanize/turnstile.py +422 -0
  100. chutils-3.7.0/src/chutils/scraping/humanize/warmer.py +622 -0
  101. chutils-3.7.0/src/chutils/scraping/nodriver.py +186 -0
  102. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/profiles/adapters/selenium.py +3 -1
  103. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/profiles/manager.py +76 -0
  104. chutils-3.7.0/src/chutils/scraping/proxy/__init__.py +64 -0
  105. chutils-3.7.0/src/chutils/scraping/proxy/adapters.py +116 -0
  106. chutils-3.7.0/src/chutils/scraping/proxy/extension.py +217 -0
  107. chutils-3.7.0/src/chutils/scraping/proxy/models.py +124 -0
  108. chutils-3.7.0/src/chutils/scraping/proxy/parser.py +122 -0
  109. chutils-3.7.0/src/chutils/scraping/proxy/pool.py +287 -0
  110. chutils-3.7.0/src/chutils/scraping/proxy/tunnel.py +379 -0
  111. chutils-3.7.0/src/chutils/scraping/testing/__init__.py +123 -0
  112. chutils-3.7.0/src/chutils/scraping/testing/assertions.py +182 -0
  113. chutils-3.7.0/src/chutils/scraping/testing/fixtures.py +112 -0
  114. chutils-3.7.0/src/chutils/scraping/testing/mocks/__init__.py +26 -0
  115. chutils-3.7.0/src/chutils/scraping/testing/mocks/dom.py +250 -0
  116. chutils-3.7.0/src/chutils/scraping/testing/mocks/nodriver.py +154 -0
  117. chutils-3.7.0/src/chutils/scraping/testing/mocks/playwright.py +203 -0
  118. chutils-3.7.0/src/chutils/scraping/testing/mocks/selenium.py +199 -0
  119. chutils-3.7.0/src/chutils/scraping/testing/server.py +329 -0
  120. chutils-3.7.0/src/chutils/scraping/testing/session.py +207 -0
  121. chutils-3.7.0/src/chutils/scraping/testing/snapshot.py +281 -0
  122. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/secret_manager/core.py +2 -1
  123. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/secret_manager/providers/gcp.py +4 -2
  124. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/tasks/core.py +0 -1
  125. {chutils-3.6.0 → chutils-3.7.0}/tests/conftest.py +4 -2
  126. chutils-3.7.0/tests/e2e/test_antidetect_e2e.py +212 -0
  127. {chutils-3.6.0 → chutils-3.7.0}/tests/integration/test_ai_lint_integration.py +52 -52
  128. {chutils-3.6.0 → chutils-3.7.0}/tests/integration/test_hooks_integration.py +43 -43
  129. {chutils-3.6.0 → chutils-3.7.0}/tests/manual/manual_test_cli_booster.py +2 -2
  130. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_diagnostics.py +1 -1
  131. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_init.py +1 -1
  132. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_required.py +157 -157
  133. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/core/test_time.py +1 -1
  134. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_ai_lint_staged.py +2 -1
  135. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_chat_context.py +252 -252
  136. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_env_parser.py +3 -3
  137. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_scaffold.py +151 -149
  138. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/di/test_di.py +1 -1
  139. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/events/test_event_bus.py +1 -1
  140. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/logger/conftest.py +2 -9
  141. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/logger/test_config_sections.py +127 -127
  142. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/metrics/test_metrics.py +2 -3
  143. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/plugins/test_integration.py +1 -1
  144. chutils-3.7.0/tests/unit/scraping/test_advanced_antidetect.py +137 -0
  145. chutils-3.7.0/tests/unit/scraping/test_antidetect_config.py +170 -0
  146. chutils-3.7.0/tests/unit/scraping/test_clearance_bridge.py +124 -0
  147. chutils-3.7.0/tests/unit/scraping/test_extraction_assertions.py +126 -0
  148. chutils-3.7.0/tests/unit/scraping/test_live_server_session.py +94 -0
  149. chutils-3.7.0/tests/unit/scraping/test_nodriver_launcher.py +135 -0
  150. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/scraping/test_profile_manager.py +37 -0
  151. chutils-3.7.0/tests/unit/scraping/test_proxy_adapters.py +70 -0
  152. chutils-3.7.0/tests/unit/scraping/test_proxy_extension.py +74 -0
  153. chutils-3.7.0/tests/unit/scraping/test_proxy_models.py +160 -0
  154. chutils-3.7.0/tests/unit/scraping/test_proxy_tunnel.py +196 -0
  155. chutils-3.7.0/tests/unit/scraping/test_pytest_plugin.py +57 -0
  156. chutils-3.7.0/tests/unit/scraping/test_scraper_mocks.py +124 -0
  157. chutils-3.7.0/tests/unit/scraping/test_scraping_proxy_pool.py +164 -0
  158. chutils-3.7.0/tests/unit/scraping/test_snapshot_recorder.py +113 -0
  159. chutils-3.7.0/tests/unit/scraping/test_turnstile_solver.py +541 -0
  160. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/secret_manager/test_secrets_required.py +87 -87
  161. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/tasks/test_scheduler.py +0 -2
  162. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_ai_lint_ignore.py +103 -103
  163. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_anticaptcha.py +130 -130
  164. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_antidetect.py +74 -0
  165. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_audit.py +5 -5
  166. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_capmonster.py +92 -92
  167. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_captcha_base.py +41 -41
  168. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_captcha_imports.py +25 -25
  169. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_concurrency_queues.py +4 -2
  170. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_crypto_dependencies.py +56 -56
  171. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_decorators_bulkhead.py +16 -9
  172. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_events_exception_group.py +46 -46
  173. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_http_streaming.py +2 -5
  174. chutils-3.7.0/tests/unit/test_http_tls_client.py +216 -0
  175. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_humanize_math.py +106 -107
  176. chutils-3.7.0/tests/unit/test_minimal_imports.py +61 -0
  177. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_nodriver_humanize.py +67 -0
  178. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_playwright_humanize.py +106 -106
  179. chutils-3.7.0/tests/unit/test_profile_warmer.py +380 -0
  180. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_rucaptcha.py +121 -121
  181. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_scraping_imports.py +42 -42
  182. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_selenium_humanize.py +134 -134
  183. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_text_dependencies.py +23 -23
  184. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_vkma_integrations.py +0 -2
  185. {chutils-3.6.0 → chutils-3.7.0}/uv.lock +1051 -284
  186. chutils-3.6.0/conductor/tracks.md +0 -35
  187. chutils-3.6.0/docs/http.md +0 -151
  188. chutils-3.6.0/docs/scraping.md +0 -337
  189. chutils-3.6.0/src/chutils/scraping/__init__.py +0 -35
  190. chutils-3.6.0/src/chutils/scraping/humanize/antidetect.py +0 -222
  191. chutils-3.6.0/src/chutils/scraping/humanize/warmer.py +0 -232
  192. chutils-3.6.0/tests/unit/test_minimal_imports.py +0 -88
  193. chutils-3.6.0/tests/unit/test_profile_warmer.py +0 -147
  194. {chutils-3.6.0 → chutils-3.7.0}/.chutilsignore +0 -0
  195. {chutils-3.6.0 → chutils-3.7.0}/.gitattributes +0 -0
  196. {chutils-3.6.0 → chutils-3.7.0}/.github/workflows/publish-docs.yml +0 -0
  197. {chutils-3.6.0 → chutils-3.7.0}/.gitignore +0 -0
  198. {chutils-3.6.0 → chutils-3.7.0}/CODE_OF_CONDUCT.md +0 -0
  199. {chutils-3.6.0 → chutils-3.7.0}/CONTRIBUTING.md +0 -0
  200. {chutils-3.6.0 → chutils-3.7.0}/GEMINI.md +0 -0
  201. {chutils-3.6.0 → chutils-3.7.0}/LICENSE +0 -0
  202. {chutils-3.6.0 → chutils-3.7.0}/README.md +0 -0
  203. {chutils-3.6.0 → chutils-3.7.0}/conductor/.gitignore +0 -0
  204. {chutils-3.6.0 → chutils-3.7.0}/conductor/GEMINI.md +0 -0
  205. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/ai_context_opt_20260728/index.md +0 -0
  206. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/ai_context_opt_20260728/metadata.json +0 -0
  207. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/ai_context_opt_20260728/plan.md +0 -0
  208. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/ai_context_opt_20260728/spec.md +0 -0
  209. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/async_lifecycle_20260728/index.md +0 -0
  210. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/async_lifecycle_20260728/metadata.json +0 -0
  211. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/async_lifecycle_20260728/plan.md +0 -0
  212. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/async_lifecycle_20260728/spec.md +0 -0
  213. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/browser_profiles_20260728/index.md +0 -0
  214. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/browser_profiles_20260728/metadata.json +0 -0
  215. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/browser_profiles_20260728/plan.md +0 -0
  216. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/browser_profiles_20260728/spec.md +0 -0
  217. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/plugins_extension_20260805/plan.md +0 -0
  218. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/plugins_extension_20260805/spec.md +0 -0
  219. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/python315_support_20260827/index.md +0 -0
  220. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/python315_support_20260827/metadata.json +0 -0
  221. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/python315_support_20260827/plan.md +0 -0
  222. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/python315_support_20260827/spec.md +0 -0
  223. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/queue_monitoring_20260728/index.md +0 -0
  224. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/queue_monitoring_20260728/metadata.json +0 -0
  225. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/queue_monitoring_20260728/plan.md +0 -0
  226. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/queue_monitoring_20260728/spec.md +0 -0
  227. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/stream_crypto_20260728/index.md +0 -0
  228. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/stream_crypto_20260728/metadata.json +0 -0
  229. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/stream_crypto_20260728/plan.md +0 -0
  230. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/stream_crypto_20260728/spec.md +0 -0
  231. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_access_20260729/index.md +0 -0
  232. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_access_20260729/metadata.json +0 -0
  233. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_access_20260729/plan.md +0 -0
  234. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_access_20260729/spec.md +0 -0
  235. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_formatting_20260729/index.md +0 -0
  236. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_formatting_20260729/metadata.json +0 -0
  237. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_formatting_20260729/plan.md +0 -0
  238. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_formatting_20260729/spec.md +0 -0
  239. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_keyboard_20260729/index.md +0 -0
  240. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_keyboard_20260729/metadata.json +0 -0
  241. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_keyboard_20260729/plan.md +0 -0
  242. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_keyboard_20260729/spec.md +0 -0
  243. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_logging_20260729/index.md +0 -0
  244. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_logging_20260729/metadata.json +0 -0
  245. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_logging_20260729/plan.md +0 -0
  246. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_logging_20260729/spec.md +0 -0
  247. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_media_20260729/index.md +0 -0
  248. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_media_20260729/metadata.json +0 -0
  249. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_media_20260729/plan.md +0 -0
  250. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_media_20260729/spec.md +0 -0
  251. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_notifier_20260729/index.md +0 -0
  252. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_notifier_20260729/metadata.json +0 -0
  253. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_notifier_20260729/plan.md +0 -0
  254. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_notifier_20260729/spec.md +0 -0
  255. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_ratelimit_20260729/index.md +0 -0
  256. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_ratelimit_20260729/metadata.json +0 -0
  257. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_ratelimit_20260729/plan.md +0 -0
  258. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_ratelimit_20260729/spec.md +0 -0
  259. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_send_file_20260729/index.md +0 -0
  260. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_send_file_20260729/metadata.json +0 -0
  261. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_send_file_20260729/plan.md +0 -0
  262. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_send_file_20260729/spec.md +0 -0
  263. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_whitelist_20260729/index.md +0 -0
  264. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_whitelist_20260729/metadata.json +0 -0
  265. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_whitelist_20260729/plan.md +0 -0
  266. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/telegram_whitelist_20260729/spec.md +0 -0
  267. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/vk_callback_20260807/index.md +0 -0
  268. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/vk_callback_20260807/metadata.json +0 -0
  269. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/vk_callback_20260807/plan.md +0 -0
  270. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/vk_callback_20260807/spec.md +0 -0
  271. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/vk_scaffold_20260807/index.md +0 -0
  272. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/vk_scaffold_20260807/metadata.json +0 -0
  273. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/vk_scaffold_20260807/plan.md +0 -0
  274. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/vk_scaffold_20260807/spec.md +0 -0
  275. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/vk_testing_20260807/index.md +0 -0
  276. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/vk_testing_20260807/metadata.json +0 -0
  277. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/vk_testing_20260807/plan.md +0 -0
  278. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/vk_testing_20260807/spec.md +0 -0
  279. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/vkma_20260807/index.md +0 -0
  280. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/vkma_20260807/metadata.json +0 -0
  281. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/vkma_20260807/plan.md +0 -0
  282. {chutils-3.6.0 → chutils-3.7.0}/conductor/archive/vkma_20260807/spec.md +0 -0
  283. {chutils-3.6.0 → chutils-3.7.0}/conductor/code_styleguides/python.md +0 -0
  284. {chutils-3.6.0 → chutils-3.7.0}/conductor/index.md +0 -0
  285. {chutils-3.6.0 → chutils-3.7.0}/conductor/product-guidelines.md +0 -0
  286. {chutils-3.6.0 → chutils-3.7.0}/conductor/setup_state.json +0 -0
  287. {chutils-3.6.0 → chutils-3.7.0}/conductor/workflow.md +0 -0
  288. {chutils-3.6.0 → chutils-3.7.0}/docs/CODE_OF_CONDUCT_RU.md +0 -0
  289. {chutils-3.6.0 → chutils-3.7.0}/docs/CONTRIBUTING_RU.md +0 -0
  290. {chutils-3.6.0 → chutils-3.7.0}/docs/INTEGRATION_AI.md +0 -0
  291. {chutils-3.6.0 → chutils-3.7.0}/docs/README_RU.md +0 -0
  292. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_examples/README.md +0 -0
  293. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_examples/configuration/README.md +0 -0
  294. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_examples/configuration/good_pattern.py +0 -0
  295. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_examples/error_handling/README.md +0 -0
  296. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_examples/error_handling/bad_pattern.py +0 -0
  297. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_examples/logging/README.md +0 -0
  298. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_examples/optional_deps/README.md +0 -0
  299. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_examples/secrets/README.md +0 -0
  300. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_examples/secrets/bad_pattern.py +0 -0
  301. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_examples/secrets/good_pattern.py +0 -0
  302. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_hints.md +0 -0
  303. {chutils-3.6.0 → chutils-3.7.0}/docs/ai_lint.md +0 -0
  304. {chutils-3.6.0 → chutils-3.7.0}/docs/audit.md +0 -0
  305. {chutils-3.6.0 → chutils-3.7.0}/docs/captcha.md +0 -0
  306. {chutils-3.6.0 → chutils-3.7.0}/docs/cli/check.md +0 -0
  307. {chutils-3.6.0 → chutils-3.7.0}/docs/cli/config.md +0 -0
  308. {chutils-3.6.0 → chutils-3.7.0}/docs/cli/db.md +0 -0
  309. {chutils-3.6.0 → chutils-3.7.0}/docs/cli/dev.md +0 -0
  310. {chutils-3.6.0 → chutils-3.7.0}/docs/cli/env.md +0 -0
  311. {chutils-3.6.0 → chutils-3.7.0}/docs/cli/index.md +0 -0
  312. {chutils-3.6.0 → chutils-3.7.0}/docs/cli/init.md +0 -0
  313. {chutils-3.6.0 → chutils-3.7.0}/docs/cli/pypi.md +0 -0
  314. {chutils-3.6.0 → chutils-3.7.0}/docs/cli/secrets.md +0 -0
  315. {chutils-3.6.0 → chutils-3.7.0}/docs/cli/show_paths.md +0 -0
  316. {chutils-3.6.0 → chutils-3.7.0}/docs/cli/template.md +0 -0
  317. {chutils-3.6.0 → chutils-3.7.0}/docs/cli/validate.md +0 -0
  318. {chutils-3.6.0 → chutils-3.7.0}/docs/custom_config_providers.md +0 -0
  319. {chutils-3.6.0 → chutils-3.7.0}/docs/index.md +0 -0
  320. {chutils-3.6.0 → chutils-3.7.0}/docs/plugins.md +0 -0
  321. {chutils-3.6.0 → chutils-3.7.0}/docs/qt.md +0 -0
  322. {chutils-3.6.0 → chutils-3.7.0}/docs/recipes.md +0 -0
  323. {chutils-3.6.0 → chutils-3.7.0}/docs/store.md +0 -0
  324. {chutils-3.6.0 → chutils-3.7.0}/docs/telegram.md +0 -0
  325. {chutils-3.6.0 → chutils-3.7.0}/docs/testing.md +0 -0
  326. {chutils-3.6.0 → chutils-3.7.0}/docs/vk_bot.md +0 -0
  327. {chutils-3.6.0 → chutils-3.7.0}/docs/vk_testing.md +0 -0
  328. {chutils-3.6.0 → chutils-3.7.0}/docs/vkma.md +0 -0
  329. {chutils-3.6.0 → chutils-3.7.0}/docs/web.md +0 -0
  330. {chutils-3.6.0 → chutils-3.7.0}/examples/.env +0 -0
  331. {chutils-3.6.0 → chutils-3.7.0}/examples/02_logging.py +0 -0
  332. {chutils-3.6.0 → chutils-3.7.0}/examples/03_secrets.py +0 -0
  333. {chutils-3.6.0 → chutils-3.7.0}/examples/04_full_example.py +0 -0
  334. {chutils-3.6.0 → chutils-3.7.0}/examples/05_different_log_levels.py +0 -0
  335. {chutils-3.6.0 → chutils-3.7.0}/examples/07_decorators_example.py +0 -0
  336. {chutils-3.6.0 → chutils-3.7.0}/examples/09_disable_keyring.py +0 -0
  337. {chutils-3.6.0 → chutils-3.7.0}/examples/10_universal_env_override.py +0 -0
  338. {chutils-3.6.0 → chutils-3.7.0}/examples/11_retry_decorator.py +0 -0
  339. {chutils-3.6.0 → chutils-3.7.0}/examples/12_secret_masking.py +0 -0
  340. {chutils-3.6.0 → chutils-3.7.0}/examples/13_pydantic_validation.py +0 -0
  341. {chutils-3.6.0 → chutils-3.7.0}/examples/15_context_logging.py +0 -0
  342. {chutils-3.6.0 → chutils-3.7.0}/examples/16_cloud_secret_managers.py +0 -0
  343. {chutils-3.6.0 → chutils-3.7.0}/examples/17_timeout_decorator.py +0 -0
  344. {chutils-3.6.0 → chutils-3.7.0}/examples/18_config_hot_reload.py +0 -0
  345. {chutils-3.6.0 → chutils-3.7.0}/examples/19_remote_config.py +0 -0
  346. {chutils-3.6.0 → chutils-3.7.0}/examples/20_opentelemetry_tracing.py +0 -0
  347. {chutils-3.6.0 → chutils-3.7.0}/examples/21_config_diagnostics.py +0 -0
  348. {chutils-3.6.0 → chutils-3.7.0}/examples/22_circuit_breaker_decorator.py +0 -0
  349. {chutils-3.6.0 → chutils-3.7.0}/examples/22_qt_logging.py +0 -0
  350. {chutils-3.6.0 → chutils-3.7.0}/examples/23_event_bus.py +0 -0
  351. {chutils-3.6.0 → chutils-3.7.0}/examples/23_qt_async.py +0 -0
  352. {chutils-3.6.0 → chutils-3.7.0}/examples/24_qt_typed_signals.py +0 -0
  353. {chutils-3.6.0 → chutils-3.7.0}/examples/24_task_scheduler.py +0 -0
  354. {chutils-3.6.0 → chutils-3.7.0}/examples/25_testing_fixtures_example.py +0 -0
  355. {chutils-3.6.0 → chutils-3.7.0}/examples/27_rate_limiting.py +0 -0
  356. {chutils-3.6.0 → chutils-3.7.0}/examples/28_dependency_injection.py +0 -0
  357. {chutils-3.6.0 → chutils-3.7.0}/examples/concurrency_scraping_usage.py +0 -0
  358. {chutils-3.6.0 → chutils-3.7.0}/examples/config.yml +0 -0
  359. {chutils-3.6.0 → chutils-3.7.0}/examples/web_client_usage.py +0 -0
  360. {chutils-3.6.0 → chutils-3.7.0}/mkdocs.yml +0 -0
  361. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/__init__.pyi +0 -0
  362. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/__main__.py +0 -0
  363. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/antigravity.md +0 -0
  364. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/audit/__init__.py +0 -0
  365. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/audit/_hash.py +0 -0
  366. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/audit/api.py +0 -0
  367. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/audit/backends/__init__.py +0 -0
  368. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/audit/backends/base.py +0 -0
  369. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/audit/backends/file.py +0 -0
  370. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/audit/backends/postgres.py +0 -0
  371. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/audit/backends/sqlite.py +0 -0
  372. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/audit/schema.py +0 -0
  373. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/cache/__init__.py +0 -0
  374. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/cache/base.py +0 -0
  375. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/cache/decorator.py +0 -0
  376. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/cache/in_memory.py +0 -0
  377. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/cache/utils.py +0 -0
  378. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/cli.py +0 -0
  379. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/cli_booster.py +0 -0
  380. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/__init__.py +0 -0
  381. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/base.py +0 -0
  382. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/check.py +0 -0
  383. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/config.py +0 -0
  384. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/db.py +0 -0
  385. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/__init__.py +0 -0
  386. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/ai_lint.py +0 -0
  387. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/base.py +0 -0
  388. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/chat_context.py +0 -0
  389. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/clean.py +0 -0
  390. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/dashboard.py +0 -0
  391. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/diagnostics.py +0 -0
  392. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/few_shot.py +0 -0
  393. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/generate_context.py +0 -0
  394. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/hooks.py +0 -0
  395. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/lock.py +0 -0
  396. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/mock.py +0 -0
  397. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/profile_imports.py +0 -0
  398. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/scaffold.py +0 -0
  399. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/setup_github_actions.py +0 -0
  400. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/sync_env.py +0 -0
  401. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/dev/watch.py +0 -0
  402. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/env.py +0 -0
  403. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/init.py +0 -0
  404. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/paths.py +0 -0
  405. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/secrets.py +0 -0
  406. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/template.py +0 -0
  407. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/utils.py +0 -0
  408. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/commands/validate.py +0 -0
  409. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/GEMINI.md +0 -0
  410. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/__init__.py +0 -0
  411. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/ast_fallback_parser.py +0 -0
  412. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/custom_providers.py +0 -0
  413. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/dev.py +0 -0
  414. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/diagnostics.py +0 -0
  415. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/generator.py +0 -0
  416. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/getters.py +0 -0
  417. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/integrations.py +0 -0
  418. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/providers.py +0 -0
  419. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/schema.py +0 -0
  420. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/sse.py +0 -0
  421. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/utils.py +0 -0
  422. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/watcher.py +0 -0
  423. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/config/webhook_server.py +0 -0
  424. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/context.py +0 -0
  425. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/crypto.py +0 -0
  426. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/db.py +0 -0
  427. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/decorators.py +0 -0
  428. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/__init__.py +0 -0
  429. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/ai_lint.py +0 -0
  430. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/ast_indexer.py +0 -0
  431. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/changelog_parser.py +0 -0
  432. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/chat_context.py +0 -0
  433. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/cleaner.py +0 -0
  434. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/constants.py +0 -0
  435. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/context/__init__.py +0 -0
  436. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/context/gitignore.py +0 -0
  437. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/context/incremental.py +0 -0
  438. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/dashboard/__init__.py +0 -0
  439. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/dashboard/indexer.py +0 -0
  440. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/dashboard/input.py +0 -0
  441. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/dashboard/tui.py +0 -0
  442. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/env_parser.py +0 -0
  443. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/env_sync.py +0 -0
  444. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/few_shot/__init__.py +0 -0
  445. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/few_shot/models.py +0 -0
  446. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/few_shot/renderer.py +0 -0
  447. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/github_actions.py +0 -0
  448. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/mock_server.py +0 -0
  449. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/models/__init__.py +0 -0
  450. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/models/base.py +0 -0
  451. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/models/index.py +0 -0
  452. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/models/node.py +0 -0
  453. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/models/symbol.py +0 -0
  454. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/profile_imports.py +0 -0
  455. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/project_metadata.py +0 -0
  456. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/rules/__init__.py +0 -0
  457. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/rules/api_map.py +0 -0
  458. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/rules/decomposition.py +0 -0
  459. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/rules/dependency_sync.py +0 -0
  460. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/rules/env.py +0 -0
  461. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/rules/integration.py +0 -0
  462. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/rules/linter_coverage.py +0 -0
  463. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/rules/manifest.py +0 -0
  464. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/rules/upgrade_check.py +0 -0
  465. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/runners.py +0 -0
  466. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/scaffold.py +0 -0
  467. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/upgrade_client.py +0 -0
  468. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/version_detector.py +0 -0
  469. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/dev/watcher.py +0 -0
  470. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/di/__init__.py +0 -0
  471. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/di/__init__.pyi +0 -0
  472. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/di/container.py +0 -0
  473. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/diagnostics/__init__.py +0 -0
  474. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/diagnostics/manager.py +0 -0
  475. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/diagnostics/models.py +0 -0
  476. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/diagnostics/web.py +0 -0
  477. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/env.pyi +0 -0
  478. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/exceptions/__init__.py +0 -0
  479. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/exceptions/audit.py +0 -0
  480. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/exceptions/base.py +0 -0
  481. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/exceptions/cache.py +0 -0
  482. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/exceptions/config.py +0 -0
  483. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/exceptions/di.py +0 -0
  484. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/exceptions/events.py +0 -0
  485. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/exceptions/logger.py +0 -0
  486. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/exceptions/resilience.py +0 -0
  487. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/exceptions/secrets.py +0 -0
  488. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/exceptions/system.py +0 -0
  489. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/exceptions/telegram.py +0 -0
  490. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/exceptions/validation.py +0 -0
  491. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/exceptions/vkma.py +0 -0
  492. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/exceptions/watcher.py +0 -0
  493. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/features.py +0 -0
  494. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/fs.py +0 -0
  495. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/http/api.py +0 -0
  496. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/http/fallback.py +0 -0
  497. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/http/resilience.py +0 -0
  498. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/http/streaming.py +0 -0
  499. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/http/tracing.py +0 -0
  500. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/logger/GEMINI.md +0 -0
  501. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/logger/__init__.py +0 -0
  502. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/logger/core.py +0 -0
  503. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/logger/formatters.py +0 -0
  504. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/logger/internal/levels.py +0 -0
  505. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/logger/internal/utils.py +0 -0
  506. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/logger/masking.py +0 -0
  507. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/metrics/__init__.py +0 -0
  508. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/metrics/base.py +0 -0
  509. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/metrics/in_memory.py +0 -0
  510. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/metrics/prometheus.py +0 -0
  511. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/metrics/timer.py +0 -0
  512. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/plugins/__init__.py +0 -0
  513. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/plugins/core.py +0 -0
  514. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/plugins/interfaces.py +0 -0
  515. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/qt/__init__.py +0 -0
  516. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/qt/asyncio.py +0 -0
  517. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/qt/logging.py +0 -0
  518. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/qt/signals.py +0 -0
  519. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/qt/widgets.py +0 -0
  520. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scaffold.py +0 -0
  521. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/captcha/__init__.py +0 -0
  522. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/captcha/anticaptcha.py +0 -0
  523. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/captcha/base.py +0 -0
  524. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/captcha/capmonster.py +0 -0
  525. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/captcha/rucaptcha.py +0 -0
  526. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/concurrency/__init__.py +0 -0
  527. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/concurrency/base.py +0 -0
  528. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/concurrency/limiter.py +0 -0
  529. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/concurrency/metrics.py +0 -0
  530. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/concurrency/models.py +0 -0
  531. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/concurrency/pool.py +0 -0
  532. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/concurrency/queues.py +0 -0
  533. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/humanize/math_utils.py +0 -0
  534. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/profiles/__init__.py +0 -0
  535. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/profiles/adapters/__init__.py +0 -0
  536. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/profiles/adapters/nodriver.py +0 -0
  537. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/profiles/adapters/playwright.py +0 -0
  538. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/profiles/models.py +0 -0
  539. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/scraping/profiles/storage.py +0 -0
  540. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/secret_manager/GEMINI.md +0 -0
  541. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/secret_manager/__init__.py +0 -0
  542. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/secret_manager/providers/__init__.py +0 -0
  543. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/secret_manager/providers/aws.py +0 -0
  544. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/secret_manager/providers/base.py +0 -0
  545. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/secret_manager/providers/dotenv.py +0 -0
  546. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/secret_manager/providers/env.py +0 -0
  547. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/secret_manager/providers/keyring_provider.py +0 -0
  548. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/store/__init__.py +0 -0
  549. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/store/backends/__init__.py +0 -0
  550. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/store/backends/base.py +0 -0
  551. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/store/backends/memcached.py +0 -0
  552. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/store/backends/memory.py +0 -0
  553. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/store/backends/redis.py +0 -0
  554. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/store/decorator.py +0 -0
  555. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/store/manager.py +0 -0
  556. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/tasks/__init__.py +0 -0
  557. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/tasks/__init__.pyi +0 -0
  558. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/telegram/__init__.py +0 -0
  559. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/telegram/access.py +0 -0
  560. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/telegram/aiogram.py +0 -0
  561. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/telegram/formatting.py +0 -0
  562. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/telegram/keyboard.py +0 -0
  563. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/telegram/logging.py +0 -0
  564. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/telegram/media.py +0 -0
  565. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/telegram/notifier.py +0 -0
  566. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/telegram/rate_limit.py +0 -0
  567. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/telegram/whitelist.py +0 -0
  568. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/templates/vk/vk-miniapp/backend/config.yml.template +0 -0
  569. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/templates/vk/vk-miniapp/backend/main.py.template +0 -0
  570. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/templates/vk/vk-miniapp/docker-compose.yml.template +0 -0
  571. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/templates/vk/vk-miniapp/frontend/App.jsx.template +0 -0
  572. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/testing/__init__.py +0 -0
  573. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/testing/fixtures.py +0 -0
  574. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/text.py +0 -0
  575. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/time.py +0 -0
  576. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/tracing.py +0 -0
  577. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/typing.py +0 -0
  578. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/validation.py +0 -0
  579. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/validation.pyi +0 -0
  580. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/vk/__init__.py +0 -0
  581. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/vk/callback/__init__.py +0 -0
  582. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/vk/callback/router.py +0 -0
  583. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/vk/testing/__init__.py +0 -0
  584. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/vk/testing/fixtures.py +0 -0
  585. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/vk/testing/generators.py +0 -0
  586. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/vkma/__init__.py +0 -0
  587. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/vkma/exceptions.py +0 -0
  588. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/vkma/integrations/__init__.py +0 -0
  589. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/vkma/integrations/aiohttp.py +0 -0
  590. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/vkma/integrations/fastapi.py +0 -0
  591. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/vkma/integrations/flask.py +0 -0
  592. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/vkma/models.py +0 -0
  593. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/vkma/testing.py +0 -0
  594. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/vkma/validator.py +0 -0
  595. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/web/__init__.py +0 -0
  596. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/web/client.py +0 -0
  597. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/web/proxy_pool.py +0 -0
  598. {chutils-3.6.0 → chutils-3.7.0}/src/chutils/web/user_agent.py +0 -0
  599. {chutils-3.6.0 → chutils-3.7.0}/tests/integration/__init__.py +0 -0
  600. {chutils-3.6.0 → chutils-3.7.0}/tests/integration/test_cli_e2e.py +0 -0
  601. {chutils-3.6.0 → chutils-3.7.0}/tests/integration/test_db_migrations.py +0 -0
  602. {chutils-3.6.0 → chutils-3.7.0}/tests/integration/test_event_loops.py +0 -0
  603. {chutils-3.6.0 → chutils-3.7.0}/tests/integration/test_examples.py +0 -0
  604. {chutils-3.6.0 → chutils-3.7.0}/tests/integration/test_masking_integration.py +0 -0
  605. {chutils-3.6.0 → chutils-3.7.0}/tests/integration/test_otel_tracing.py +0 -0
  606. {chutils-3.6.0 → chutils-3.7.0}/tests/integration/test_remote_config_integration.py +0 -0
  607. {chutils-3.6.0 → chutils-3.7.0}/tests/integration/test_setup_github_actions_integration.py +0 -0
  608. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/conftest.py +0 -0
  609. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli.py +0 -0
  610. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_booster.py +0 -0
  611. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_check.py +0 -0
  612. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_config.py +0 -0
  613. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_config_cmd.py +0 -0
  614. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_config_schema.py +0 -0
  615. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_dev.py +0 -0
  616. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_dev_cmd.py +0 -0
  617. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_dev_lock.py +0 -0
  618. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_dev_tree.py +0 -0
  619. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_dev_watch.py +0 -0
  620. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_extras_suggestion.py +0 -0
  621. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_init_interactive.py +0 -0
  622. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_paths.py +0 -0
  623. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_pypi.py +0 -0
  624. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_rich.py +0 -0
  625. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_rich_width.py +0 -0
  626. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_secrets.py +0 -0
  627. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_setup_github_actions.py +0 -0
  628. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_template.py +0 -0
  629. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_utils_internal.py +0 -0
  630. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/cli/test_cli_validate.py +0 -0
  631. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config.py +0 -0
  632. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_ast_parser.py +0 -0
  633. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_dev.py +0 -0
  634. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_diagnostics.py +0 -0
  635. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_env.py +0 -0
  636. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_env_loading.py +0 -0
  637. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_generator.py +0 -0
  638. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_integrations.py +0 -0
  639. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_json.py +0 -0
  640. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_pydantic.py +0 -0
  641. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_schema.py +0 -0
  642. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_sse.py +0 -0
  643. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_sse_integration.py +0 -0
  644. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_tracing.py +0 -0
  645. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_universal_env.py +0 -0
  646. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_utils.py +0 -0
  647. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_validation_group.py +0 -0
  648. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_watcher.py +0 -0
  649. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_config_webhook.py +0 -0
  650. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_custom_config_providers.py +0 -0
  651. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_priority_unification.py +0 -0
  652. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/config/test_remote_config.py +0 -0
  653. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/core/test_ast_indexer.py +0 -0
  654. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/core/test_ast_indexer_abstract.py +0 -0
  655. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/core/test_ast_indexer_graph.py +0 -0
  656. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/core/test_ast_indexer_layers.py +0 -0
  657. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/core/test_ast_indexer_metadata.py +0 -0
  658. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/core/test_cache.py +0 -0
  659. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/core/test_dev_models.py +0 -0
  660. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/core/test_exceptions.py +0 -0
  661. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/core/test_features.py +0 -0
  662. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/core/test_fs.py +0 -0
  663. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/core/test_lifecycle.py +0 -0
  664. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/core/test_thread_safety.py +0 -0
  665. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/decorators/test_decorator_circuit_breaker.py +0 -0
  666. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/decorators/test_decorator_retry.py +0 -0
  667. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/decorators/test_decorator_timeout.py +0 -0
  668. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/decorators/test_decorators.py +0 -0
  669. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/decorators/test_rate_limit.py +0 -0
  670. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_ai_lint.py +0 -0
  671. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_changelog_parser.py +0 -0
  672. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_cleaner.py +0 -0
  673. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_context_generator.py +0 -0
  674. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_env_sync.py +0 -0
  675. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_generate_few_shot.py +0 -0
  676. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_linter_coverage_rule.py +0 -0
  677. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_mock_server.py +0 -0
  678. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_runners.py +0 -0
  679. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_setup_github_actions.py +0 -0
  680. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_upgrade_check_rule.py +0 -0
  681. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_upgrade_client.py +0 -0
  682. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_version_detector.py +0 -0
  683. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/dev/test_watcher.py +0 -0
  684. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/logger/test_basics.py +0 -0
  685. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/logger/test_compression.py +0 -0
  686. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/logger/test_configuration.py +0 -0
  687. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/logger/test_context.py +0 -0
  688. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/logger/test_env_control.py +0 -0
  689. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/logger/test_files.py +0 -0
  690. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/logger/test_json_format.py +0 -0
  691. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/logger/test_logger_rich_width.py +0 -0
  692. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/logger/test_masking.py +0 -0
  693. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/logger/test_performance_security.py +0 -0
  694. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/logger/test_rich.py +0 -0
  695. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/logger/test_rotation.py +0 -0
  696. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/plugins/test_interfaces.py +0 -0
  697. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/plugins/test_plugins.py +0 -0
  698. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/scraping/test_profile_adapters.py +0 -0
  699. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/scraping/test_profile_storage.py +0 -0
  700. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/scraping/test_queue_metrics.py +0 -0
  701. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/scraping/test_worker_metrics.py +0 -0
  702. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/secret_manager/test_secret_manager.py +0 -0
  703. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/secret_manager/test_secret_manager_env.py +0 -0
  704. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/secret_manager/test_secret_manager_providers.py +0 -0
  705. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/telegram/test_access.py +0 -0
  706. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/telegram/test_aiogram_filter.py +0 -0
  707. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/telegram/test_aiogram_middleware.py +0 -0
  708. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/telegram/test_formatting.py +0 -0
  709. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/telegram/test_keyboard.py +0 -0
  710. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/telegram/test_logging.py +0 -0
  711. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/telegram/test_notifier.py +0 -0
  712. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/telegram/test_telegram_rate_limit.py +0 -0
  713. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/telegram/test_whitelist.py +0 -0
  714. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_async_web_client.py +0 -0
  715. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_audit_phase2.py +0 -0
  716. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_cli_db.py +0 -0
  717. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_concurrency_imports.py +0 -0
  718. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_concurrency_limiter.py +0 -0
  719. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_concurrency_pool.py +0 -0
  720. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_config_alias_choices.py +0 -0
  721. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_config_fallback.py +0 -0
  722. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_crypto.py +0 -0
  723. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_crypto_stream.py +0 -0
  724. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_dashboard.py +0 -0
  725. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_db_init.py +0 -0
  726. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_db_operations.py +0 -0
  727. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_diagnostics.py +0 -0
  728. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_env.py +0 -0
  729. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_http_api.py +0 -0
  730. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_http_client.py +0 -0
  731. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_http_fallback.py +0 -0
  732. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_http_resilience.py +0 -0
  733. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_http_tracing.py +0 -0
  734. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_init_templates.py +0 -0
  735. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_install_hooks.py +0 -0
  736. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_profile_imports.py +0 -0
  737. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_proxy_pool.py +0 -0
  738. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_qt_asyncio.py +0 -0
  739. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_qt_logging.py +0 -0
  740. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_qt_shim.py +0 -0
  741. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_qt_signals.py +0 -0
  742. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_qt_widgets.py +0 -0
  743. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_store_backends_external.py +0 -0
  744. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_store_integrations.py +0 -0
  745. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_store_manager.py +0 -0
  746. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_store_memory.py +0 -0
  747. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_telegram_media.py +0 -0
  748. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_telegram_send_file.py +0 -0
  749. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_text.py +0 -0
  750. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_user_agent.py +0 -0
  751. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_validation.py +0 -0
  752. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_vk_callback_fastapi.py +0 -0
  753. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_vk_callback_router.py +0 -0
  754. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_vk_testing_fixtures.py +0 -0
  755. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_vk_testing_generators.py +0 -0
  756. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_vkma_core.py +0 -0
  757. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_web_client.py +0 -0
  758. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/test_web_imports.py +0 -0
  759. {chutils-3.6.0 → chutils-3.7.0}/tests/unit/testing/test_fixtures.py +0 -0
@@ -1,46 +1,46 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches: [ main, master ]
6
- pull_request:
7
- branches: [ main, master ]
8
-
9
- jobs:
10
- test-and-lint:
11
- runs-on: ubuntu-latest
12
- strategy:
13
- matrix:
14
- python-version: [ '3.10', '3.11', '3.12', '3.13', '3.14', '3.15-dev' ]
15
-
16
-
17
- steps:
18
- - uses: actions/checkout@v4
19
-
20
- - name: Set up Python ${{ matrix.python-version }}
21
- uses: actions/setup-python@v5
22
- with:
23
- python-version: ${{ matrix.python-version }}
24
-
25
- - name: Install uv
26
- uses: astral-sh/setup-uv@v5
27
- with:
28
- enable-cache: true
29
- version: "latest"
30
-
31
- - name: Install dependencies
32
- run: |
33
- uv sync --all-extras
34
-
35
- - name: Run Tests
36
- run: |
37
- uv run pytest
38
-
39
- - name: Run Type Checking (Mypy)
40
- run: |
41
- uv run mypy src
42
-
43
- - name: Run AI-Readiness Audit
44
- run: |
45
- uv run python -m chutils dev ai-lint --soft-mode
46
-
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, master ]
6
+ pull_request:
7
+ branches: [ main, master ]
8
+
9
+ jobs:
10
+ test-and-lint:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: [ '3.10', '3.11', '3.12', '3.13', '3.14', '3.15-dev' ]
15
+
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Set up Python ${{ matrix.python-version }}
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+
25
+ - name: Install uv
26
+ uses: astral-sh/setup-uv@v5
27
+ with:
28
+ enable-cache: true
29
+ version: "latest"
30
+
31
+ - name: Install dependencies
32
+ run: |
33
+ uv sync --all-extras
34
+
35
+ - name: Run Tests
36
+ run: |
37
+ uv run pytest
38
+
39
+ - name: Run Type Checking (Mypy)
40
+ run: |
41
+ uv run mypy src
42
+
43
+ - name: Run AI-Readiness Audit
44
+ run: |
45
+ uv run python -m chutils dev ai-lint --soft-mode
46
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: chutils
3
- Version: 3.6.0
3
+ Version: 3.7.0
4
4
  Summary: Набор простых и удобных утилит для Python, который избавляет от рутины при работе с конфигурацией и логированием в новых проектах.
5
5
  Author-email: Chu4hel <sergeiivanov636@gmail.com>
6
6
  License-Expression: MIT
@@ -11,6 +11,8 @@ Requires-Dist: python-dotenv>=1.2.2
11
11
  Requires-Dist: pyyaml>=6.0.3
12
12
  Provides-Extra: aws
13
13
  Requires-Dist: boto3>=1.34.0; extra == 'aws'
14
+ Provides-Extra: camoufox
15
+ Requires-Dist: camoufox>=0.4.0; extra == 'camoufox'
14
16
  Provides-Extra: captcha
15
17
  Requires-Dist: httpx>=0.27.0; extra == 'captcha'
16
18
  Provides-Extra: crypto
@@ -71,6 +73,8 @@ Provides-Extra: testing
71
73
  Requires-Dist: pytest>=9.0.3; extra == 'testing'
72
74
  Provides-Extra: text
73
75
  Requires-Dist: rapidfuzz>=3.9.0; extra == 'text'
76
+ Provides-Extra: tls
77
+ Requires-Dist: curl-cffi>=0.7.0; extra == 'tls'
74
78
  Provides-Extra: vk
75
79
  Requires-Dist: pydantic<3.0.0,>=2.13.4; extra == 'vk'
76
80
  Provides-Extra: vkma
@@ -128,8 +128,10 @@
128
128
  # ---------------------------------------------------------------------------
129
129
 
130
130
  "src/chutils/scraping/**/*.py" = ["docs/scraping.md"]
131
+ "new:src/chutils/scraping/nodriver.py" = ["docs/scraping.md"]
131
132
  "src/chutils/scraping/captcha/**/*.py" = ["docs/captcha.md"]
132
133
 
134
+
133
135
  # ---------------------------------------------------------------------------
134
136
  # Модуль аудита
135
137
  # ---------------------------------------------------------------------------
@@ -1,9 +1,9 @@
1
1
  ---
2
- chutils_version: 3.6.0
3
- project_version: 3.6.0
4
- git_commit: a622ebf7170639f85d8e299bf4763768c2e87719
5
- generated_at: 2026-09-07T19:30:12.995418+00:00
6
- project_hash: fb14b689767aaa8d9826e388bf1bc7b7627bbc60d975d32d8e73cbab59a05758
2
+ chutils_version: 3.7.0
3
+ project_version: 3.7.0
4
+ git_commit: 5cb29a30832f6b1d6e3af1c4572da491e9a76968 (dirty)
5
+ generated_at: 2026-09-15T14:49:04.299233+00:00
6
+ project_hash: 58ba4b8fbabcd20573314c01c78c3ef9decdf6006d6aac4c12d7be9c84989f7a
7
7
  ---
8
8
 
9
9
  # Public API Map: chutils
@@ -104,6 +104,8 @@ project_hash: fb14b689767aaa8d9826e388bf1bc7b7627bbc60d975d32d8e73cbab59a05758
104
104
  | `SseConfigClient` | class | `(self, url: 'str', on_event: 'Callable[[SseEvent], None] \| None' = None, on_reload: 'Callable[[], None] \| None' = None, headers: 'dict[str, str] \| None' = None, timeout: 'float' = 30.0, reconnect_delay: 'float' = 1.0, max_reconnect_delay: 'float' = 60.0) -> 'None'` | Клиент для постоянного подключения к SSE-серверу обновлений конфигурации. |
105
105
  | `SseEvent` | class | `(self, event: 'str' = 'message', data: 'str' = '', event_id: 'str \| None' = None, retry: 'int \| None' = None) -> 'None'` | Представляет отдельное событие Server-Sent Events (SSE). |
106
106
  | `StoreManager` | class | `(self, backend: 'BaseStoreBackend \| None' = None, serializer: 'str \| Any' = 'json', prefix: 'str' = '') -> 'None'` | Центральный менеджер Key-Value хранилища. |
107
+ | `TLSAsyncClient` | class | `(self, impersonate: 'str' = 'chrome120', proxy: 'ProxyConfig \| str \| None' = None, proxy_pool: 'ProxyPool \| None' = None, fallback_to_standard: 'bool' = False, timeout: 'float' = 30.0, **kwargs: 'Any') -> 'None'` | Асинхронный HTTP-клиент с поддержкой TLS/HTTP2 Client Impersonation (curl-cffi). |
108
+ | `TLSSession` | class | `(self, impersonate: 'str' = 'chrome120', proxy: 'ProxyConfig \| str \| None' = None, proxy_pool: 'ProxyPool \| None' = None, fallback_to_standard: 'bool' = False, timeout: 'float' = 30.0, **kwargs: 'Any') -> 'None'` | Синхронный HTTP-клиент с поддержкой TLS/HTTP2 Client Impersonation (curl-cffi). |
107
109
  | `TelegramLogHandler` | class | `(self, bot_token: 'str \| None' = None, chat_id: 'int \| str \| None' = None, level: 'int' = 40, rate_limit_per_min: 'int' = 10) -> 'None'` | Handler стандартного модуля logging для отправки критических логов в Telegram. |
108
110
  | `TelegramLoggingMiddleware` | class | `(self, logger_instance: 'Any' = None) -> 'None'` | Middleware контекстного логирования и измерений времени выполнения для aiogram 3.x. |
109
111
  | `TelegramRateLimiter` | class | `(self, rate: 'int' = 1, per: 'float' = 1.0) -> 'None'` | Движок ограничений вызовов (Rate Limiter) для Telegram-ботов. |
@@ -120,17 +122,17 @@ project_hash: fb14b689767aaa8d9826e388bf1bc7b7627bbc60d975d32d8e73cbab59a05758
120
122
  | `aget_config` | function | `(model: 'type[T] \| None' = None) -> 'JSONDict \| T'` | Асинхронная версия get_config. |
121
123
  | `aget_config_value` | function | `(section: 'str', key: 'str', fallback: 'Any' = None, config: 'JSONDict \| None' = None, required: 'bool' = False) -> 'Any'` | Асинхронно получает произвольное значение из конфигурации. |
122
124
  | `allowed_only` | function | `(manager: 'AccessListManager \| None' = None, allowed_ids: 'list[int] \| None' = None, allowed_usernames: 'list[str] \| None' = None, blocked_ids: 'list[int] \| None' = None, blocked_usernames: 'list[str] \| None' = None, refusal_text: 'str \| None' = '⛔ У вас нет доступа к этой функции', silent: 'bool' = False, raise_on_denied: 'bool' = False) -> 'Callable[[F], F]'` | Декоратор ограничения доступа по белым и черным спискам. |
123
- | `apply_antidetect_nodriver` | function | `(tab: Any, *, webgl_vendor: str = 'Google Inc. (NVIDIA)', webgl_renderer: str = 'ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0, D3D11)', hardware_concurrency: int = 8, device_memory: int = 8) -> None` | Применяет JS-инъекции анти-детекта к вкладке (Tab) nodriver. |
124
- | `apply_antidetect_playwright` | function | `(context: Any, *, webgl_vendor: str = 'Google Inc. (NVIDIA)', webgl_renderer: str = 'ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0, D3D11)', hardware_concurrency: int = 8, device_memory: int = 8) -> None` | Применяет JS-инъекции анти-детекта к контексту Playwright. |
125
- | `apply_antidetect_selenium` | function | `(driver: Any, *, webgl_vendor: str = 'Google Inc. (NVIDIA)', webgl_renderer: str = 'ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0, D3D11)', hardware_concurrency: int = 8, device_memory: int = 8) -> None` | Применяет JS-инъекции анти-детекта к сессии Selenium. |
125
+ | `apply_antidetect_nodriver` | function | `(tab: 'Any', *, config: 'AntidetectConfig \| None' = None, webgl_vendor: 'str' = 'Google Inc. (NVIDIA)', webgl_renderer: 'str' = 'ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0, D3D11)', hardware_concurrency: 'int' = 8, device_memory: 'int' = 8, stealth_minimal: 'bool' = True, session_seed: 'str \| int' = 1337, client_hints: 'dict[str, Any] \| None' = None) -> 'None'` | Применяет JS-инъекции анти-детекта к вкладке (Tab) nodriver. |
126
+ | `apply_antidetect_playwright` | function | `(context: 'Any', *, config: 'AntidetectConfig \| None' = None, webgl_vendor: 'str' = 'Google Inc. (NVIDIA)', webgl_renderer: 'str' = 'ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0, D3D11)', hardware_concurrency: 'int' = 8, device_memory: 'int' = 8, stealth_minimal: 'bool' = False, session_seed: 'str \| int' = 1337, client_hints: 'dict[str, Any] \| None' = None) -> 'None'` | Применяет JS-инъекции анти-детекта к контексту Playwright. |
127
+ | `apply_antidetect_selenium` | function | `(driver: 'Any', *, config: 'AntidetectConfig \| None' = None, webgl_vendor: 'str' = 'Google Inc. (NVIDIA)', webgl_renderer: 'str' = 'ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0, D3D11)', hardware_concurrency: 'int' = 8, device_memory: 'int' = 8, stealth_minimal: 'bool' = False, session_seed: 'str \| int' = 1337, client_hints: 'dict[str, Any] \| None' = None) -> 'None'` | Применяет JS-инъекции анти-детекта к сессии Selenium. |
126
128
  | `are_paths_initialized` | function | `() -> bool` | Проверяет, были ли инициализированы пути к проекту и файлам конфигурации. |
127
129
  | `asave_config_value` | function | `(section: 'str', key: 'str', value: 'Any', cfg_file: 'str \| None' = None, save_to_local: 'bool' = False, notify: 'bool' = True) -> 'bool'` | Асинхронно сохраняет одно значение в конфигурационном файле. |
128
- | `async_click` | function | `(page: Any, selector: str \| None = None, x: int \| None = None, y: int \| None = None, start: tuple[int, int] \| None = None, algorithm: str = 'windmouse', button: str = 'left') -> None` | Имитирует реалистичный клик мышью (с плавным наведением, микропаузами и удержанием кнопки). |
130
+ | `async_click` | function | `(page: Any, selector: str \| None = None, x: int \| None = None, y: int \| None = None, start: tuple[int, int] \| None = None, algorithm: str = 'windmouse', button: str = 'left', hold_time: tuple[float, float] = (0.05, 0.12)) -> None` | Имитирует реалистичный клик мышью (с плавным наведением, микропаузами и удержанием кнопки). |
129
131
  | `async_human_sleep` | function | `(min_seconds: float, max_seconds: float) -> None` | Асинхронно задерживает выполнение на случайное время, имитируя поведение человека. |
130
132
  | `async_lifecycle` | function | `(setup_signals: 'bool' = True, auto_cleanup_subsystems: 'bool' = True) -> 'AsyncLifecycleContext'` | Возвращает контекстный менеджер для управления жизненным циклом ресурсов. |
131
133
  | `async_move_mouse` | function | `(page: Any, x: int, y: int, start: tuple[int, int] \| None = None, steps: int = 30, delay_between_steps: float = 0.01, algorithm: str = 'bezier') -> None` | Имитирует плавное перемещение мыши Playwright или nodriver. |
132
134
  | `async_scroll_to` | function | `(page: Any, x: int, y: int, selector: str \| None = None, steps: int = 10, delay_between_steps: float = 0.01) -> None` | Имитирует плавный скроллинг Playwright или nodriver. |
133
- | `async_type_text` | function | `(page: Any, selector: str, text: str, error_rate: float = 0.05, speed_wpm: float = 40.0) -> None` | Имитирует ввод текста с опечатками Playwright или nodriver. |
135
+ | `async_type_text` | function | `(page: Any, selector: str, text: str, error_rate: float = 0.05, speed_wpm: float = 40.0, key_hold_time: tuple[float, float] = (0.04, 0.09)) -> None` | Имитирует ввод текста с опечатками Playwright или nodriver. |
134
136
  | `audit` | module | | chutils.audit — Неизменяемый журнал событий аудита. |
135
137
  | `audit_context` | function | `(action: 'str', actor: 'str', *, target: 'str \| None' = None, backend: 'object') -> 'Generator[_AuditContextState, None, None]'` | Контекстный менеджер для регистрации события аудита в блоке кода. |
136
138
  | `audit_event` | function | `(action: 'str', actor: '_ActorOrCallable' = 'system', *, target: '_TargetOrCallable' = None, backend: 'object') -> 'Callable'` | Декоратор для автоматической регистрации события аудита при вызове функции. |
@@ -143,10 +145,12 @@ project_hash: fb14b689767aaa8d9826e388bf1bc7b7627bbc60d975d32d8e73cbab59a05758
143
145
  | `cleanup_paths` | function | `(*paths: 'str \| Path', retries: 'int' = 3, delay: 'float' = 0.1, on_locked: "Literal['raise', 'rename_orphan', 'warn']" = 'warn', orphan_collision: "Literal['raise', 'overwrite', 'unique']" = 'raise') -> 'None'` | Пакетное удаление нескольких путей. |
144
146
  | `clear_context` | function | `() -> 'None'` | Полностью очищает текущий контекст. |
145
147
  | `cli_command` | function | `(func: ~F) -> ~F` | Декоратор для превращения функции в CLI-команду. |
146
- | `click` | function | `(driver: Any, selector: str \| None = None, x: int \| None = None, y: int \| None = None, start: tuple[int, int] \| None = None, algorithm: str = 'windmouse') -> None` | Имитирует реалистичный клик мышью Selenium. |
148
+ | `click` | function | `(driver: Any, selector: str \| None = None, x: int \| None = None, y: int \| None = None, start: tuple[int, int] \| None = None, algorithm: str = 'windmouse', hold_time: tuple[float, float] = (0.05, 0.12)) -> None` | Имитирует реалистичный клик мышью Selenium. |
147
149
  | `config` | module | | Модуль для работы с конфигурацией. |
148
150
  | `container` | constant | | Легковесный IoC/DI контейнер. |
149
151
  | `context` | module | | |
152
+ | `create_curl_async_session` | function | `(impersonate: 'str', proxy: 'str \| None' = None, **kwargs: 'Any') -> 'Any'` | Создает асинхронную сессию curl_cffi с заданным профилем impersonate. |
153
+ | `create_curl_session` | function | `(impersonate: 'str', proxy: 'str \| None' = None, **kwargs: 'Any') -> 'Any'` | Создает синхронную сессию curl_cffi с заданным профилем impersonate. |
150
154
  | `create_http_span` | function | `(method: 'str', url: 'str', tracer_name: 'str' = 'chutils.http') -> 'object \| None'` | Создаёт OTEL-спан для исходящего HTTP-запроса. |
151
155
  | `crypto` | module | | Модуль для портативного детерминированного шифрования данных. |
152
156
  | `dashboard` | module | | Интерактивный TUI-дашборд для CLI-команд проекта. |
@@ -166,6 +170,7 @@ project_hash: fb14b689767aaa8d9826e388bf1bc7b7627bbc60d975d32d8e73cbab59a05758
166
170
  | `events` | module | | Модуль шины событий (In-Memory Event Bus). |
167
171
  | `exceptions` | module | | |
168
172
  | `export_schema` | function | `(model: type[pydantic.main.BaseModel] \| str, output_path: str \| pathlib.Path \| None = None, indent: int = 4) -> str` | Генерирует JSON Schema для Pydantic модели и опционально сохраняет в файл. |
173
+ | `extract_clearance_cookies` | function | `(target: 'Any') -> 'Any'` | Извлекает cookies (включая cf_clearance) и User-Agent из сессии браузера. |
169
174
  | `few_shot` | module | | |
170
175
  | `fs` | module | | Модуль для надежных операций с файловой системой. |
171
176
  | `generate_env_template` | function | `(model_class: 'type[BaseModel]', prefix: 'str' = 'CH') -> 'str'` | Генерирует .env шаблон (плоский формат). |
@@ -175,7 +180,8 @@ project_hash: fb14b689767aaa8d9826e388bf1bc7b7627bbc60d975d32d8e73cbab59a05758
175
180
  | `generate_yaml_template` | function | `(model_class: 'type[BaseModel]', indent: 'int' = 0) -> 'str'` | Генерирует YAML шаблон на основе Pydantic модели с комментариями. |
176
181
  | `get_all_config_paths` | function | `(cfg_file: str \| None = None) -> tuple[str \| None, str \| None, str \| None]` | Возвращает пути к основному, специфичному для окружения и локальному файлам конфигурации. |
177
182
  | `get_base_dir` | function | `() -> str \| None` | Возвращает абсолютный путь к корневой директории проекта. |
178
- | `get_browser_launch_args` | function | `() -> list[str]` | Возвращает набор аргументов запуска браузера для скрытия автоматизации. |
183
+ | `get_browser_launch_args` | function | `() -> 'list[str]'` | Возвращает расширенный набор аргументов запуска браузера для скрытия автоматизации. |
184
+ | `get_client_hints` | function | `(user_agent: 'str \| None' = None) -> 'dict[str, Any]'` | Генерирует словарь согласованных Client Hints (navigator.userAgentData) на основе User-Agent. |
179
185
  | `get_config` | function | `(model: 'type[T] \| None' = None, remote_url: 'str \| None' = None, remote_auth: 'tuple[str, str] \| None' = None, polling_interval: 'int \| None' = None, sse_url: 'str \| None' = None, sse_headers: 'dict[str, str] \| None' = None) -> 'JSONDict \| T'` | Загружает и объединяет конфигурацию из всех доступных источников. |
180
186
  | `get_config_boolean` | function | `(section: 'str', key: 'str', fallback: 'bool' = False, config: 'JSONDict \| None' = None, required: 'bool' = False) -> 'bool'` | Получает булево значение из конфигурации. |
181
187
  | `get_config_file_path` | function | `() -> str \| None` | Возвращает путь к основному файлу конфигурации, который используется в данный момент. |
@@ -199,6 +205,7 @@ project_hash: fb14b689767aaa8d9826e388bf1bc7b7627bbc60d975d32d8e73cbab59a05758
199
205
  | `is_otel_enabled` | function | `() -> 'bool'` | Проверяет, доступен ли OpenTelemetry и не отключен ли он. |
200
206
  | `is_rich_enabled` | function | `() -> 'bool'` | Централизованная проверка: доступен ли Rich и разрешен ли он настройками. |
201
207
  | `is_significant_difference` | function | `(text1: str, text2: str, threshold: float = 0.9) -> bool` | Проверяет, является ли разница между двумя текстами значительной. |
208
+ | `launch_camoufox` | function | `(headless: 'bool' = True, os: 'str' = 'windows', **kwargs: 'Any') -> 'Any'` | Создает и возвращает контекстный менеджер / сессию браузера AsyncCamoufox. |
202
209
  | `lifecycle` | module | | Управление жизненным циклом приложения. |
203
210
  | `load_ai_lint_config` | function | `(cli_args: 'JSONDict \| None' = None) -> 'JSONDict'` | Загружает и объединяет конфигурацию для ai-lint из всех источников. |
204
211
  | `log_function_details` | function | `(func: collections.abc.Callable[~P, ~R]) -> collections.abc.Callable[~P, ~R]` | Декоратор для логирования деталей вызова функции. |
@@ -35,13 +35,13 @@ loaded_chutils = [m for m in sys.modules if m.startswith('chutils.')]
35
35
  print(json.dumps({{"duration": end - start, "modules": loaded_chutils}}))
36
36
  """
37
37
  result = subprocess.run(
38
- [sys.executable, "-c", script], capture_output=True, text=True
38
+ [sys.executable, "-c", script], capture_output=True, text=True, check=False
39
39
  )
40
40
  if result.returncode != 0:
41
41
  print(f"Error: {result.stderr}")
42
42
  try:
43
43
  return json.loads(result.stdout)
44
- except:
44
+ except Exception:
45
45
  return None
46
46
  return json.loads(result.stdout)
47
47
 
@@ -0,0 +1,5 @@
1
+ # Track advanced_antidetect_e2e_20260910 Context
2
+
3
+ - [Specification](./spec.md)
4
+ - [Implementation Plan](./plan.md)
5
+ - [Metadata](./metadata.json)
@@ -0,0 +1,4 @@
1
+ {
2
+ "summary": "Индексный файл index.md для трека advanced_antidetect_e2e_20260910",
3
+ "updatedAt": "2026-09-10T12:54:36.199351700Z"
4
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "track_id": "advanced_antidetect_e2e_20260910",
3
+ "type": "feature",
4
+ "status": "new",
5
+ "created_at": "2026-09-10T15:53:30+03:00",
6
+ "updated_at": "2026-09-10T15:53:30+03:00",
7
+ "description": "Улучшение антидетекта (Web Workers, stack traces, cookie bridge) и E2E тесты"
8
+ }
@@ -0,0 +1,29 @@
1
+ # Implementation Plan: Продвинутый антидетект и E2E тесты
2
+
3
+ ## Phase 1: Усиление JS-антидетекта (Web Workers & V8 Stacks)
4
+ - [x] Task: Написать unit-тесты для перехвата Worker и маскировки стектрейсов
5
+ - [x] Написать тесты на генерацию JS-кода с перехватом `Worker` и `SharedWorker`
6
+ - [x] Написать тесты на генерацию чистого `Error.prototype.stack` в геттерах
7
+ - [x] Task: Модернизация src/chutils/scraping/humanize/antidetect.py
8
+ - [x] Добавить в JS-скрипт перехват `window.Worker` и `window.SharedWorker` с инъекцией преамбулы
9
+ - [x] Улучшить хелпер `makeNative` для маскировки стектрейсов вызовов V8
10
+ - [x] Task: Conductor - User Manual Verification 'Phase 1: Worker & Stack Protection' (Protocol in workflow.md)
11
+
12
+ ## Phase 2: Мост Cookie/Headers (Браузер -> TLSAsyncClient)
13
+ - [x] Task: Написать unit-тесты для extract_clearance_cookies
14
+ - [x] Написать тесты для извлечения кук и User-Agent из Playwright, Selenium и Nodriver моков
15
+ - [x] Task: Реализация extract_clearance_cookies и интеграция с TLSAsyncClient
16
+ - [x] Реализовать `extract_clearance_cookies` в `src/chutils/scraping/humanize/antidetect.py`
17
+ - [x] Добавить фабричный метод `from_browser_session` в `TLSAsyncClient` / `TLSSession`
18
+ - [x] Task: Conductor - User Manual Verification 'Phase 2: Cookie Bridge' (Protocol in workflow.md)
19
+
20
+ ## Phase 3: E2E Тесты и финальная верификация
21
+ - [x] Task: Реализация E2E тестов в tests/e2e/test_antidetect_e2e.py
22
+ - [x] Реализовать E2E проверку TLS/JA4 профилей через peet.ws
23
+ - [x] Реализовать проверку чистоты окружения Worker и navigator
24
+ - [x] Реализовать сквозной тест передачи сессии из браузера в TLSAsyncClient
25
+ - [x] Task: Экспорт, документация и проверки качества
26
+ - [x] Добавить экспорт новых утилит в `src/chutils/__init__.py` и `src/chutils/scraping/__init__.py`
27
+ - [x] Обновить документацию `docs/scraping.md` и `docs/http.md`
28
+ - [x] Прогнать `pytest`, `mypy --strict`, `ruff check`, `ruff format --check`, `chutils dev lock --force`, `chutils dev ai-lint`
29
+ - [x] Task: Conductor - User Manual Verification 'Phase 3: E2E Testing & Verification' (Protocol in workflow.md)
@@ -0,0 +1,4 @@
1
+ {
2
+ "summary": "План реализации plan.md трека advanced_antidetect_e2e_20260910",
3
+ "updatedAt": "2026-09-10T12:54:30.892555600Z"
4
+ }
@@ -0,0 +1,25 @@
1
+ # Specification: Продвинутый антидетект (Web Workers, V8 Stacks, Cookie Bridge) и E2E тесты
2
+
3
+ ## 1. Overview
4
+ Трек направлен на закрытие ключевых векторов обнаружения автоматизации (утечки через изолированные Web Workers/SharedWorkers, следы в Error.prototype.stack) и создание сквозного моста передачи сессионных cookie/заголовков из браузеров (Playwright/Camoufox/Nodriver) в высокоскоростные TLS-клиенты (TLSSession/TLSAsyncClient), а также покрытие функционала E2E-тестами.
5
+
6
+ ## 2. Functional Requirements
7
+ - **Web Workers & SharedWorkers Protection**:
8
+ - Внедрение перехвата `window.Worker` и `window.SharedWorker` в `antidetect.py`.
9
+ - Автоматическая инъекция защитного преамбул-скрипта (очистка `navigator.webdriver`, подмена `navigator.userAgentData`, маскировка `toString`) при создании Worker через URL или Blob.
10
+ - **V8 Stack Traces Cloaking**:
11
+ - Улучшение `makeNative` для предотвращения утечек имен патч-функций и неверных строк стека при искусственном вызове ошибок внутри геттеров.
12
+ - **Cookie/Header Bridge (`extract_clearance_cookies`)**:
13
+ - Функция `extract_clearance_cookies(target: Any) -> dict[str, Any]` с извлечением кук (`cf_clearance`, `__cf_bm` и др.), заголовков и User-Agent из Playwright `BrowserContext`/`Page`, Selenium WebDriver и Nodriver Tab.
14
+ - Метод интеграции или фабрика создания `TLSAsyncClient.from_browser_session(session_or_page)`.
15
+ - **E2E Testing Suite**:
16
+ - Создание `tests/e2e/test_antidetect_e2e.py` (с маркером `@pytest.mark.e2e`):
17
+ - Тест валидации JA3/JA4 и HTTP/2 на реальном сервисе `https://tls.peet.ws/api/all`.
18
+ - Тест изоляции Web Workers и прототипов в браузере.
19
+ - Сквозной тест передачи сессии из браузера в `TLSAsyncClient`.
20
+
21
+ ## 3. Acceptance Criteria
22
+ 1. Web Workers не выдают `navigator.webdriver === true`.
23
+ 2. Стектрейсы ошибок в пропатченных свойствах не содержат артефактов стороннего JS кода.
24
+ 3. Функция `extract_clearance_cookies` успешно работает со всеми поддерживаемыми драйверами с graceful fallback.
25
+ 4. Все E2E и unit-тесты проходят, mypy strict, ruff и ai-lint без ошибок и предупреждений.
@@ -0,0 +1,4 @@
1
+ {
2
+ "summary": "Спецификация трека advanced_antidetect_e2e_20260910",
3
+ "updatedAt": "2026-09-10T12:54:27.348681300Z"
4
+ }
@@ -0,0 +1,5 @@
1
+ # Track nodriver_antidetect_20260910 Context
2
+
3
+ - [Specification](./spec.md)
4
+ - [Implementation Plan](./plan.md)
5
+ - [Metadata](./metadata.json)
@@ -0,0 +1,8 @@
1
+ {
2
+ "track_id": "nodriver_antidetect_20260910",
3
+ "type": "feature",
4
+ "status": "completed",
5
+ "created_at": "2026-09-10T02:42:00Z",
6
+ "updated_at": "2026-09-10T02:42:00Z",
7
+ "description": "Улучшение антидетекта и скрытия автоматизации nodriver (маскировка JS, нативные дескрипторы, микропаузы, Permissions API)"
8
+ }
@@ -0,0 +1,41 @@
1
+ # Implementation Plan: nodriver Anti-Detect & Stealth Enhancement
2
+
3
+ ## Phase 1: JavaScript Anti-Tampering & Permissions Synchronization
4
+ - [x] Task: TDD - Тесты для улучшенной JS-инъекции (защита toString, WebGL2, Permissions API)
5
+ - [x] Написать unit-тесты для проверки `Function.prototype.toString` (`[native code]`)
6
+ - [x] Написать unit-тесты для одновременного патчинга WebGL1 и WebGL2
7
+ - [x] Написать unit-тесты эмуляции Permissions API и Notification
8
+ - [x] Task: Реализация улучшений JS-маскировки в `antidetect.py`
9
+ - [x] Реализовать функцию `makeNative` для маскировки строкового представления функций
10
+ - [x] Добавить обработку `WebGL2RenderingContext`
11
+ - [x] Добавить синхронизацию `navigator.permissions.query` и `Notification.permission`
12
+ - [x] Привести в соответствие дескрипторы свойств `navigator`
13
+ - [x] Task: Conductor - User Manual Verification 'Phase 1: JavaScript Anti-Tampering & Permissions Synchronization' (Protocol in workflow.md)
14
+
15
+ ## Phase 2: nodriver Stealth Minimal Mode & Browser Flags
16
+ - [x] Task: TDD - Тесты для режима stealth_minimal и флагов запуска браузера
17
+ - [x] Добавить тесты для `apply_antidetect_nodriver` с параметром `stealth_minimal=True`
18
+ - [x] Протестировать обновленный список флагов запуска `get_browser_launch_args`
19
+ - [x] Task: Реализация `stealth_minimal` и обновление аргументов запуска
20
+ - [x] Добавить аргумент `stealth_minimal` в функцию `apply_antidetect_nodriver`
21
+ - [x] Исключить модификацию Canvas и WebGL при `stealth_minimal=True`
22
+ - [x] Обновить флаги в `get_browser_launch_args` (современный headless, подавление детекта автоматизации)
23
+ - [x] Task: Conductor - User Manual Verification 'Phase 2: nodriver Stealth Minimal Mode & Browser Flags' (Protocol in workflow.md)
24
+
25
+ ## Phase 3: Humanized Hold Time in CDP Input Actions
26
+ - [x] Task: TDD - Тесты для микропауз удержания кнопок мыши и клавиш
27
+ - [x] Написать тесты для проверки пауз между mousePressed и mouseReleased в `async_click`
28
+ - [x] Написать тесты для проверки задержек удержания keyDown/keyUp в `async_type_text`
29
+ - [x] Task: Реализация микропауз удержания в `actions.py`
30
+ - [x] Добавить параметры `hold_time_min` и `hold_time_max` в `async_click` для CDP
31
+ - [x] Добавить эмуляцию задержки нажатия клавиш в `async_type_text` для nodriver
32
+ - [x] Task: Conductor - User Manual Verification 'Phase 3: Humanized Hold Time in CDP Input Actions' (Protocol in workflow.md)
33
+
34
+ ## Phase 4: Documentation, AI Context Sync & Final Integration
35
+ - [x] Task: Обновление документации
36
+ - [x] Обновить `docs/scraping.md` с описанием новых параметров и возможностей антидетекта
37
+ - [x] Проверить соответствие Google docstrings в затронутых файлах
38
+ - [x] Task: Синхронизация AI-контекста и линтинг
39
+ - [x] Сгенерировать контекст через `uv run chutils dev generate-context`
40
+ - [x] Запустить `uv run chutils dev ai-lint` и `uv run pytest` для валидации всего набора тестов
41
+ - [x] Task: Conductor - User Manual Verification 'Phase 4: Documentation, AI Context Sync & Final Integration' (Protocol in workflow.md)
@@ -0,0 +1,31 @@
1
+ # Specification: nodriver Anti-Detect & Stealth Enhancement (`chutils.scraping.humanize`)
2
+
3
+ ## 1. Overview
4
+ Улучшение механизмов маскировки автоматизации и антидетекта для `nodriver` (а также `playwright` и `selenium`) в модуле `chutils.scraping.humanize`. Цель: устранение прямых признаков вмешательства (Tampering) в окружение JavaScript, поддержка WebGL2, нативная маскировка `Function.prototype.toString`, согласование дескрипторов свойств, реализация режима `stealth_minimal` и добавление физиологических микропауз удержания (Hold Time) для CDP-ввода.
5
+
6
+ ## 2. Functional Requirements
7
+ 1. **Качественная маскировка JavaScript (Anti-Tampering)**:
8
+ - Защита `Function.prototype.toString`: все подмененные встроенные функции должны возвращать `"function [name]() { [native code] }"`, а вызов `.toString()` на них самих — корректную нативную строку.
9
+ - Корректная эмуляция дескрипторов: `Object.getOwnPropertyDescriptor` на `navigator` и прототипах должен возвращать стандартные атрибуты без явных следов переопределения (`enumerable`, `configurable`, `writable`).
10
+ - Патчинг WebGL2: одновременная и согласованная подмена параметров вендора и рендерера в `WebGLRenderingContext` и `WebGL2RenderingContext`.
11
+ - Синхронизация Permissions API: приведение к консистентному состоянию `Notification.permission` и `navigator.permissions.query({name: 'notifications'})`.
12
+ 2. **Режим `stealth_minimal` для nodriver**:
13
+ - Параметр `stealth_minimal: bool = False` в `apply_antidetect_nodriver()`.
14
+ - При активном флаге не вносить синтетический шум в Canvas (`getImageData`) и не переопределять WebGL-параметры, если используется полноценный установленный Google Chrome, чтобы не нарушать естественный отпечаток железа.
15
+ 3. **Физиологические микропаузы (Hold Time)**:
16
+ - Добавить настраиваемый диапазон задержки удержания (Hold Time) для событий клика мыши (`mousePressed` -> `mouseReleased`) в `async_click` (по умолчанию 50–120 мс).
17
+ - Добавить задержку удержания между нажатием и отпусканием клавиш (`keyDown` -> `keyUp`) в `async_type_text` (по умолчанию 40–90 мс) при работе через CDP.
18
+ 4. **Оптимизация флагов запуска**:
19
+ - Обновить `get_browser_launch_args()` для добавления флагов исключения предупреждений автоматизации и поддержки современного режима headless.
20
+
21
+ ## 3. Non-Functional Requirements
22
+ - Строгая типизация Python 3.10+ (без устаревших `typing.Optional`, `typing.List` и без `Any` в сигнатурах публичного API).
23
+ - Обратная совместимость с существующими сигнатурами функций `apply_antidetect_*` и `async_click`/`async_type_text`.
24
+ - Высокое покрытие модульными тестами (>90%).
25
+
26
+ ## 4. Acceptance Criteria
27
+ - [ ] Вызовы `.toString()` на подмененных функциях в JS-инъекциях возвращают `[native code]`.
28
+ - [ ] Параметры WebGL вендора и рендерера корректно подменяются как для WebGL 1, так и для WebGL 2.
29
+ - [ ] `apply_antidetect_nodriver(..., stealth_minimal=True)` не внедряет искажения Canvas и WebGL.
30
+ - [ ] Ввод текста и клики через CDP в `nodriver` содержат микропаузы удержания клавиш и кнопок мыши.
31
+ - [ ] Все существующие и новые unit-тесты успешно проходят через `uv run pytest`.
@@ -0,0 +1,5 @@
1
+ # Track nodriver_launch_turnstile_fix_20260910 Context
2
+
3
+ - [Specification](./spec.md)
4
+ - [Implementation Plan](./plan.md)
5
+ - [Metadata](./metadata.json)
@@ -0,0 +1,9 @@
1
+ {
2
+ "track_id": "nodriver_launch_turnstile_fix_20260910",
3
+ "type": "feature",
4
+ "status": "completed",
5
+ "created_at": "2026-09-10T18:51:00Z",
6
+ "updated_at": "2026-09-10T19:04:00Z",
7
+
8
+ "description": "Исправление координат Turnstile, поддержка Shadow DOM и фабрика launch_nodriver с AntidetectConfig"
9
+ }