direct-cli 0.5.3__tar.gz → 0.5.4__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 (445) hide show
  1. {direct_cli-0.5.3 → direct_cli-0.5.4}/AGENTS.md +21 -1
  2. {direct_cli-0.5.3 → direct_cli-0.5.4}/CHANGELOG.md +208 -0
  3. {direct_cli-0.5.3 → direct_cli-0.5.4}/PKG-INFO +149 -49
  4. {direct_cli-0.5.3 → direct_cli-0.5.4}/README.md +147 -47
  5. {direct_cli-0.5.3 → direct_cli-0.5.4}/README_ru.md +84 -38
  6. direct_cli-0.5.4/direct_cli/_auth_hints.py +21 -0
  7. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.py +10 -0
  8. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.pyi +6 -1
  9. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/api.py +72 -1
  10. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/auth.py +124 -17
  11. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/browser/_chrome_crypto.py +27 -5
  12. direct_cli-0.5.4/direct_cli/browser/ad_elements.py +376 -0
  13. direct_cli-0.5.4/direct_cli/browser/auth.py +114 -0
  14. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/browser/diagnostics.py +63 -86
  15. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/browser/masters.py +169 -102
  16. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/browser/session.py +25 -44
  17. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/browser/store.py +16 -4
  18. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/cli.py +82 -6
  19. direct_cli-0.5.4/direct_cli/commands/ad_elements.py +69 -0
  20. direct_cli-0.5.4/direct_cli/commands/auth.py +1400 -0
  21. direct_cli-0.5.4/direct_cli/commands/browser_session.py +48 -0
  22. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/history.py +2 -3
  23. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/masters.py +118 -463
  24. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/reports.py +38 -7
  25. direct_cli-0.5.4/direct_cli/optional_output.py +107 -0
  26. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/output.py +8 -1
  27. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/smoke_matrix.py +16 -2
  28. direct_cli-0.5.4/direct_cli/translations/auth.json +98 -0
  29. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/reports.json +4 -0
  30. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli.egg-info/PKG-INFO +149 -49
  31. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli.egg-info/SOURCES.txt +11 -0
  32. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli.egg-info/requires.txt +1 -1
  33. {direct_cli-0.5.3 → direct_cli-0.5.4}/pyproject.toml +13 -4
  34. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/build_api_coverage_report.py +7 -0
  35. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/test_dangerous_commands.sh +3 -2
  36. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/test_safe_commands.sh +4 -0
  37. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/conftest.py +40 -1
  38. direct_cli-0.5.4/tests/fixtures/ad_elements_payloads.json +1254 -0
  39. direct_cli-0.5.4/tests/test_ad_elements.py +326 -0
  40. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_api_coverage.py +56 -2
  41. direct_cli-0.5.4/tests/test_api_retry.py +189 -0
  42. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_auth_bw.py +5 -3
  43. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_auth_oauth.py +34 -28
  44. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_auth_op.py +5 -3
  45. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_chrome_crypto.py +19 -0
  46. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_comprehensive.py +50 -0
  47. direct_cli-0.5.4/tests/test_credential_provenance.py +394 -0
  48. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_common.py +73 -0
  49. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_masters.py +363 -207
  50. direct_cli-0.5.4/tests/test_optional_output.py +191 -0
  51. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_playwright_session.py +96 -31
  52. direct_cli-0.5.4/tests/test_unified_auth.py +763 -0
  53. direct_cli-0.5.3/direct_cli/commands/auth.py +0 -564
  54. direct_cli-0.5.3/direct_cli/commands/browser_session.py +0 -180
  55. direct_cli-0.5.3/direct_cli/translations/auth.json +0 -25
  56. {direct_cli-0.5.3 → direct_cli-0.5.4}/.env.example +0 -0
  57. {direct_cli-0.5.3 → direct_cli-0.5.4}/.github/copilot-instructions.md +0 -0
  58. {direct_cli-0.5.3 → direct_cli-0.5.4}/.github/workflows/api-coverage.yml +0 -0
  59. {direct_cli-0.5.3 → direct_cli-0.5.4}/.github/workflows/claude.yml +0 -0
  60. {direct_cli-0.5.3 → direct_cli-0.5.4}/.github/workflows/quality.yml +0 -0
  61. {direct_cli-0.5.3 → direct_cli-0.5.4}/.gitignore +0 -0
  62. {direct_cli-0.5.3 → direct_cli-0.5.4}/.mcp.json +0 -0
  63. {direct_cli-0.5.3 → direct_cli-0.5.4}/CLAUDE.md +0 -0
  64. {direct_cli-0.5.3 → direct_cli-0.5.4}/MANIFEST.in +0 -0
  65. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/__init__.py +0 -0
  66. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_autotargeting.py +0 -0
  67. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_bidding_strategy.py +0 -0
  68. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_captcha.py +0 -0
  69. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_deprecated.py +0 -0
  70. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_flag_validation.py +0 -0
  71. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_smoke_probes.py +0 -0
  72. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/__init__.py +0 -0
  73. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/__init__.py +0 -0
  74. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/endpoints.py +0 -0
  75. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/exceptions.py +0 -0
  76. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/resource_mapping.py +0 -0
  77. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/v4/__init__.py +0 -0
  78. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.py +0 -0
  79. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.pyi +0 -0
  80. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/v4/resource_mapping.py +0 -0
  81. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/browser/__init__.py +0 -0
  82. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/browser/_clock.py +0 -0
  83. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/browser/change_history.py +0 -0
  84. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/__init__.py +0 -0
  85. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_batch.py +0 -0
  86. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_campaigns_base.py +0 -0
  87. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_campaigns_cpm_banner.py +0 -0
  88. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_campaigns_dynamic.py +0 -0
  89. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_campaigns_mobile_app.py +0 -0
  90. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_campaigns_smart.py +0 -0
  91. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_campaigns_text.py +0 -0
  92. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_campaigns_unified.py +0 -0
  93. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_execute.py +0 -0
  94. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_get.py +0 -0
  95. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_lifecycle.py +0 -0
  96. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_set_bids.py +0 -0
  97. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/adextensions.py +0 -0
  98. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/adgroups.py +0 -0
  99. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/adimages.py +0 -0
  100. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/__init__.py +0 -0
  101. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/_cli.py +0 -0
  102. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/base.py +0 -0
  103. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/batch.py +0 -0
  104. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/builder.py +0 -0
  105. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/mobile_app.py +0 -0
  106. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/objects.py +0 -0
  107. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/responsive.py +0 -0
  108. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/shopping.py +0 -0
  109. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/text.py +0 -0
  110. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/advideos.py +0 -0
  111. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/agencyclients.py +0 -0
  112. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/audiencetargets.py +0 -0
  113. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/balance.py +0 -0
  114. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/bidmodifiers.py +0 -0
  115. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/bids.py +0 -0
  116. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/businesses.py +0 -0
  117. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/campaigns.py +0 -0
  118. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/changes.py +0 -0
  119. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/clients.py +0 -0
  120. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/creatives.py +0 -0
  121. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/dictionaries.py +0 -0
  122. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/dynamicads.py +0 -0
  123. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/dynamicfeedadtargets.py +0 -0
  124. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/feeds.py +0 -0
  125. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/keywordbids.py +0 -0
  126. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/keywords.py +0 -0
  127. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/keywordsresearch.py +0 -0
  128. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/leads.py +0 -0
  129. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/negativekeywordsharedsets.py +0 -0
  130. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/retargeting.py +0 -0
  131. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/sitelinks.py +0 -0
  132. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/smartadtargets.py +0 -0
  133. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/strategies.py +0 -0
  134. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/trackingparams.py +0 -0
  135. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/turbopages.py +0 -0
  136. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4account.py +0 -0
  137. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4adimage.py +0 -0
  138. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4events.py +0 -0
  139. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4finance.py +0 -0
  140. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4forecast.py +0 -0
  141. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4goals.py +0 -0
  142. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4keywords.py +0 -0
  143. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4shells.py +0 -0
  144. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4tags.py +0 -0
  145. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4wordstat.py +0 -0
  146. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/vcards.py +0 -0
  147. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/i18n.py +0 -0
  148. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/reports_coverage.py +0 -0
  149. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/tracking_params.py +0 -0
  150. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/adextensions.json +0 -0
  151. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/adgroups.json +0 -0
  152. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/adimages.json +0 -0
  153. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/ads.json +0 -0
  154. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/advideos.json +0 -0
  155. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/agencyclients.json +0 -0
  156. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/audiencetargets.json +0 -0
  157. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/balance.json +0 -0
  158. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/bidmodifiers.json +0 -0
  159. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/bids.json +0 -0
  160. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/businesses.json +0 -0
  161. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/campaigns.json +0 -0
  162. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/changes.json +0 -0
  163. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/clients.json +0 -0
  164. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/common.json +0 -0
  165. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/creatives.json +0 -0
  166. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/dictionaries.json +0 -0
  167. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/dynamicads.json +0 -0
  168. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/dynamicfeedadtargets.json +0 -0
  169. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/feeds.json +0 -0
  170. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/keywordbids.json +0 -0
  171. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/keywords.json +0 -0
  172. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/keywordsresearch.json +0 -0
  173. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/leads.json +0 -0
  174. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/negativekeywordsharedsets.json +0 -0
  175. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/retargeting.json +0 -0
  176. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/sitelinks.json +0 -0
  177. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/smartadtargets.json +0 -0
  178. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/strategies.json +0 -0
  179. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/turbopages.json +0 -0
  180. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4account.json +0 -0
  181. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4adimage.json +0 -0
  182. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4events.json +0 -0
  183. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4finance.json +0 -0
  184. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4forecast.json +0 -0
  185. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4goals.json +0 -0
  186. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4keywords.json +0 -0
  187. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4shells.json +0 -0
  188. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4tags.json +0 -0
  189. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4wordstat.json +0 -0
  190. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/vcards.json +0 -0
  191. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/utils.py +0 -0
  192. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/v4/__init__.py +0 -0
  193. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/v4/emit.py +0 -0
  194. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/v4/money.py +0 -0
  195. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/v4/parse.py +0 -0
  196. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/v4_contracts.py +0 -0
  197. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/wsdl_coverage.py +0 -0
  198. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli.egg-info/dependency_links.txt +0 -0
  199. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli.egg-info/entry_points.txt +0 -0
  200. {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli.egg-info/top_level.txt +0 -0
  201. {direct_cli-0.5.3 → direct_cli-0.5.4}/docs/audits/API_COVERAGE.md +0 -0
  202. {direct_cli-0.5.3 → direct_cli-0.5.4}/docs/audits/PROJECT_WIRE_SHAPE_AUDIT_2026-05-30.md +0 -0
  203. {direct_cli-0.5.3 → direct_cli-0.5.4}/docs/audits/WIRE_SHAPE_TRIAGE_2026-05-30.md +0 -0
  204. {direct_cli-0.5.3 → direct_cli-0.5.4}/docs/audits/issue-198-mutating-wsdl-audit.md +0 -0
  205. {direct_cli-0.5.3 → direct_cli-0.5.4}/docs/audits/wire_shape.json +0 -0
  206. {direct_cli-0.5.3 → direct_cli-0.5.4}/docs/superpowers/plans/2026-04-12-issue-32-completion.md +0 -0
  207. {direct_cli-0.5.3 → direct_cli-0.5.4}/docs/superpowers/specs/2026-04-23-vendor-tapi-yandex-direct-design.md +0 -0
  208. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/anonymize_cassettes.py +0 -0
  209. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/audit_wire_shape.py +0 -0
  210. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/build_api_coverage_checklist.py +0 -0
  211. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/build_wsdl_optional_field_audit.py +0 -0
  212. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/check_all_docs_urls.py +0 -0
  213. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/check_reports_drift.py +0 -0
  214. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/check_wsdl_drift.py +0 -0
  215. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/measure_criteria_limits.py +0 -0
  216. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/patch_vendor_imports.py +0 -0
  217. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/preflight_check.sh +0 -0
  218. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/probe_drift_urls.sh +0 -0
  219. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/recon_761_utm_split.py +0 -0
  220. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/recon_774_audit_saved_utm.py +0 -0
  221. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/recon_774_utm_reorder.py +0 -0
  222. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/recon_812_video_upload.py +0 -0
  223. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/recon_871_bidmodifiers_enum.py +0 -0
  224. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/refresh_reports_cache.py +0 -0
  225. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/refresh_wsdl_cache.py +0 -0
  226. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/release_pypi.sh +0 -0
  227. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/sandbox_write_audit.py +0 -0
  228. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/sandbox_write_live.py +0 -0
  229. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/test_sandbox_write.sh +0 -0
  230. {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/update_vendor.sh +0 -0
  231. {direct_cli-0.5.3 → direct_cli-0.5.4}/setup.cfg +0 -0
  232. {direct_cli-0.5.3 → direct_cli-0.5.4}/setup.py +0 -0
  233. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/API_COVERAGE.md +0 -0
  234. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/API_ISSUE_AUDIT.md +0 -0
  235. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/MANUAL_COVERAGE.md +0 -0
  236. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/WSDL_OPTIONAL_FIELD_AUDIT.md +0 -0
  237. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/__init__.py +0 -0
  238. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/_cli_tree.py +0 -0
  239. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/_orphan_store.py +0 -0
  240. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/api_coverage_payloads.py +0 -0
  241. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yaml +0 -0
  242. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteAdGroups.test_add_update_delete.yaml +0 -0
  243. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteAdImages.test_add_delete.yaml +0 -0
  244. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteAds.test_add_text_ad_update_delete.yaml +0 -0
  245. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteAudienceTargets.test_add_delete.yaml +0 -0
  246. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteBidModifiersAdd.test_add_delete_mobile.yaml +0 -0
  247. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteBidModifiersSet.test_set_without_id_is_rejected.yaml +0 -0
  248. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteBids.test_set_bid.yaml +0 -0
  249. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteBidsRead.test_bids_get.yaml +0 -0
  250. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteBidsRead.test_bids_set_auto.yaml +0 -0
  251. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteCampaignDraftLifecycle.test_draft_create_get_delete.yaml +0 -0
  252. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteCampaigns.test_campaign_lifecycle.yaml +0 -0
  253. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yaml +0 -0
  254. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yaml +0 -0
  255. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteKeywordBids.test_set_keyword_bid.yaml +0 -0
  256. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteKeywords.test_add_update_delete.yaml +0 -0
  257. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteNegativeKeywordSharedSets.test_add_update_delete.yaml +0 -0
  258. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yaml +0 -0
  259. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteRetargetingUpdate.test_retargeting_update.yaml +0 -0
  260. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteSitelinks.test_add_delete.yaml +0 -0
  261. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml +0 -0
  262. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteStrategies.test_strategies_lifecycle.yaml +0 -0
  263. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteVCards.test_add_delete.yaml +0 -0
  264. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_balance_get_no_shared_account.yaml +0 -0
  265. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[adextensions_get].yaml +0 -0
  266. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[adgroups_get].yaml +0 -0
  267. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[adimages_get].yaml +0 -0
  268. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[ads_get].yaml +0 -0
  269. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[advideos_get].yaml +0 -0
  270. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[audiencetargets_get].yaml +0 -0
  271. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[bidmodifiers_get].yaml +0 -0
  272. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[bids_get].yaml +0 -0
  273. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[businesses_get].yaml +0 -0
  274. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[campaigns_get].yaml +0 -0
  275. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[changes_check].yaml +0 -0
  276. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[changes_check_campaigns].yaml +0 -0
  277. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[changes_check_dictionaries].yaml +0 -0
  278. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[clients_get].yaml +0 -0
  279. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[creatives_get].yaml +0 -0
  280. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[dictionaries_get].yaml +0 -0
  281. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[dynamicads_get].yaml +0 -0
  282. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[dynamicfeedadtargets_get].yaml +0 -0
  283. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[feeds_get].yaml +0 -0
  284. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[keywordbids_get].yaml +0 -0
  285. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[keywords_get].yaml +0 -0
  286. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[keywordsresearch_deduplicate].yaml +0 -0
  287. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[keywordsresearch_has_search_volume].yaml +0 -0
  288. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[leads_get].yaml +0 -0
  289. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[negativekeywordsharedsets_get].yaml +0 -0
  290. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[reports_get].yaml +0 -0
  291. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[retargeting_get].yaml +0 -0
  292. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[sitelinks_get].yaml +0 -0
  293. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[smartadtargets_get].yaml +0 -0
  294. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[strategies_get].yaml +0 -0
  295. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[turbopages_get].yaml +0 -0
  296. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[v4adimage_get].yaml +0 -0
  297. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[v4events_get_events_log].yaml +0 -0
  298. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[v4finance_get_clients_units].yaml +0 -0
  299. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[v4forecast_list].yaml +0 -0
  300. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[v4goals_get_stat_goals].yaml +0 -0
  301. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[v4tags_get_campaigns].yaml +0 -0
  302. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[v4wordstat_list_reports].yaml +0 -0
  303. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[vcards_get].yaml +0 -0
  304. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_v4account_get_accounts_no_shared_account.yaml +0 -0
  305. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_v4finance_check_payment_unknown_transaction.yaml +0 -0
  306. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_v4forecast_get_unknown_forecast.yaml +0 -0
  307. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_v4goals_get_retargeting_goals_server_error.yaml +0 -0
  308. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_v4tags_get_banners_server_error.yaml +0 -0
  309. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_v4wordstat_get_report_unknown_report.yaml +0 -0
  310. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_adgroups_add_update_delete.yaml +0 -0
  311. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_adimages_add_get_delete.yaml +0 -0
  312. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_ads_add_update_delete.yaml +0 -0
  313. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_ads_suspend_resume_archive_unarchive.yaml +0 -0
  314. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_advideos_add_get.yaml +0 -0
  315. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_audiencetargets_add_delete.yaml +0 -0
  316. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_audiencetargets_suspend_resume.yaml +0 -0
  317. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_bids_set.yaml +0 -0
  318. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_campaign_create_get_delete.yaml +0 -0
  319. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_creatives_chain_advideo_to_creative.yaml +0 -0
  320. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_dynamicads_add_delete.yaml +0 -0
  321. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_dynamicads_suspend_resume.yaml +0 -0
  322. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_feeds_add_update_delete.yaml +0 -0
  323. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_keywordbids_set.yaml +0 -0
  324. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_keywords_add_update_delete.yaml +0 -0
  325. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_keywords_suspend_resume.yaml +0 -0
  326. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_retargeting_add_update_delete.yaml +0 -0
  327. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_sitelinks_add_get_delete.yaml +0 -0
  328. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_smartadtargets_add_update_delete.yaml +0 -0
  329. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_smartadtargets_suspend_resume.yaml +0 -0
  330. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_strategies_add_update_archive_unarchive.yaml +0 -0
  331. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_grid_campaigns.json +0 -0
  332. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_wizard_create.html +0 -0
  333. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_wizard_draft_overview.html +0 -0
  334. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_wizard_edit_moderation.html +0 -0
  335. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_wizard_edit_name.html +0 -0
  336. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_wizard_edit_stage_a.html +0 -0
  337. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_wizard_edit_stage_b.html +0 -0
  338. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_wizard_edit_stage_d.html +0 -0
  339. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_wizard_overview.html +0 -0
  340. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/test-video.mp4 +0 -0
  341. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/user_action_log.json +0 -0
  342. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/reports_cache/raw/fields-list.html +0 -0
  343. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/reports_cache/raw/headers.html +0 -0
  344. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/reports_cache/raw/period.html +0 -0
  345. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/reports_cache/raw/spec.html +0 -0
  346. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/reports_cache/raw/type.html +0 -0
  347. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/reports_cache/spec.json +0 -0
  348. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_adgroups_build_adgroup_object.py +0 -0
  349. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_adgroups_build_adgroup_update_object.py +0 -0
  350. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_ads_build_ad_object.py +0 -0
  351. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_ads_build_ad_update_object.py +0 -0
  352. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_audit_wire_shape.py +0 -0
  353. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_auth_write_json.py +0 -0
  354. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_autotargeting.py +0 -0
  355. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_balance.py +0 -0
  356. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_bidding_strategy_constants.py +0 -0
  357. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_cassette_integrity.py +0 -0
  358. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_change_history.py +0 -0
  359. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_changes.py +0 -0
  360. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_check_all_docs_urls.py +0 -0
  361. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_cli.py +0 -0
  362. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_cli_contract.py +0 -0
  363. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run.py +0 -0
  364. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_adgroups.py +0 -0
  365. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_ads.py +0 -0
  366. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_bids.py +0 -0
  367. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_campaigns.py +0 -0
  368. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_clients.py +0 -0
  369. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_extensions.py +0 -0
  370. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_keywords.py +0 -0
  371. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_shared.py +0 -0
  372. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_strategies.py +0 -0
  373. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_strategy_smart.py +0 -0
  374. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_strategy_text.py +0 -0
  375. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_strategy_unified.py +0 -0
  376. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_targets.py +0 -0
  377. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_env_loading.py +0 -0
  378. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_field_names_option.py +0 -0
  379. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_flag_validation.py +0 -0
  380. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_handle_api_errors.py +0 -0
  381. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_i18n.py +0 -0
  382. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_integration.py +0 -0
  383. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_integration_write.py +0 -0
  384. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_low_coverage_payloads.py +0 -0
  385. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_read_cassettes.py +0 -0
  386. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_reference_output.py +0 -0
  387. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_reports_drift.py +0 -0
  388. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_reports_parsing.py +0 -0
  389. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_sandbox_write_audit.py +0 -0
  390. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_smoke_matrix.py +0 -0
  391. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_transport_contract.py +0 -0
  392. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_unknown_option_hints.py +0 -0
  393. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4_contracts.py +0 -0
  394. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4_exit_codes.py +0 -0
  395. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4_foundation.py +0 -0
  396. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4_live_contracts.py +0 -0
  397. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4_output_options.py +0 -0
  398. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4_runtime_shape.py +0 -0
  399. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4_safety.py +0 -0
  400. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4account.py +0 -0
  401. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4adimage.py +0 -0
  402. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4events.py +0 -0
  403. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4finance_money.py +0 -0
  404. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4finance_read.py +0 -0
  405. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4forecast.py +0 -0
  406. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4goals.py +0 -0
  407. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4keywords.py +0 -0
  408. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4meta.py +0 -0
  409. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4tags.py +0 -0
  410. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4wordstat.py +0 -0
  411. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v5_live_write.py +0 -0
  412. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_vendor_imports.py +0 -0
  413. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_wsdl_parity_gate.py +0 -0
  414. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/adextensions.xml +0 -0
  415. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/adgroups.xml +0 -0
  416. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/adimages.xml +0 -0
  417. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/ads.xml +0 -0
  418. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/advideos.xml +0 -0
  419. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/agencyclients.xml +0 -0
  420. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/audiencetargets.xml +0 -0
  421. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/bidmodifiers.xml +0 -0
  422. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/bids.xml +0 -0
  423. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/businesses.xml +0 -0
  424. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/campaigns.xml +0 -0
  425. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/changes.xml +0 -0
  426. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/clients.xml +0 -0
  427. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/creatives.xml +0 -0
  428. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/dictionaries.xml +0 -0
  429. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/dynamicfeedadtargets.xml +0 -0
  430. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/dynamictextadtargets.xml +0 -0
  431. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/feeds.xml +0 -0
  432. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/imports/adextensiontypes.xsd +0 -0
  433. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/imports/general.xsd +0 -0
  434. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/imports/generalclients.xsd +0 -0
  435. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/keywordbids.xml +0 -0
  436. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/keywords.xml +0 -0
  437. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/keywordsresearch.xml +0 -0
  438. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/leads.xml +0 -0
  439. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/negativekeywordsharedsets.xml +0 -0
  440. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/retargetinglists.xml +0 -0
  441. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/sitelinks.xml +0 -0
  442. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/smartadtargets.xml +0 -0
  443. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/strategies.xml +0 -0
  444. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/turbopages.xml +0 -0
  445. {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/vcards.xml +0 -0
@@ -35,13 +35,33 @@ Naming rules:
35
35
 
36
36
  ### Input Rules
37
37
 
38
- - All user-facing input must be passed only through typed CLI flags.
38
+ - In default headless mode, all user-facing input must be passed only through typed CLI flags.
39
+ - Authentication input prompts require explicit `direct auth login --interactive`.
39
40
  - `--json` is not part of the public CLI contract.
40
41
  - User-facing parameters must not be passed through `--json`.
41
42
  - The CLI must not accept `SelectionCriteria`, nested payloads, update payloads, bidding rules, or any other user-facing command input through `--json`.
42
43
  - Typed flags and JSON blobs must not be mixed as part of one public command contract.
43
44
  - If the API requires a complex object, the CLI must expose explicit flags or subcommands instead of forwarding raw JSON.
44
45
 
46
+ ### Authorization Execution Mode
47
+
48
+ - Authorization is headless and non-interactive by default, including when stdin and stdout are terminals. TTY detection must never enable login dialogs or browser UI by itself.
49
+ - `direct auth login` defaults to the headless API flow: print the authorization URL and accept the completion code later through typed flags or explicit stdin input.
50
+ - Login menus and OAuth code prompts require `direct auth login --interactive`.
51
+ - Manual browser login requires explicit `--interactive` or `--headful`. `--allow-no-tty` only overrides the terminal check; it does not authorize browser UI by itself.
52
+ - Chrome import is headless by default. Failed headless verification must not retry in a visible browser automatically.
53
+ - Missing or expired credentials in ordinary commands produce an actionable error, never an implicit login.
54
+ - Saving credentials into an existing profile requires explicit `--force`; the headless completion and token import refuse to overwrite otherwise.
55
+
56
+ ### Data Safety — No Silent Overwrites
57
+
58
+ - Stored user data (auth profiles, credentials, folder bindings, browser sessions) is never replaced silently.
59
+ - A write is either the command's declared purpose (the command then reports what was replaced) or requires an explicit confirmation flag (`--force`). Ordinary commands never write stored user data as a side effect.
60
+ - Overwriting an existing auth profile requires explicit `--force` on the CLI layer and `overwrite=True` on the helper layer; the refusal names the current owner's login.
61
+ - Replacing an existing `YANDEX_DIRECT_TOKEN` in the folder `.env` prints a warning naming the previous owner.
62
+ - New write paths for stored user data must go through the guarded helpers (`save_oauth_profile`, `save_env_credentials`); bypassing the guard is a contract violation.
63
+ - Production API mutations are always explicit commands, classified SAFE / WRITE_SANDBOX / DANGEROUS in `direct_cli/smoke_matrix.py`.
64
+
45
65
  ### Command Formatting Rules
46
66
 
47
67
  - Every canonical CLI command must be written strictly on a single line.
@@ -1,5 +1,213 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ### BREAKING CHANGES
6
+
7
+ **`auth login`/`auth status`/`auth logout` use `api|browser` subcommands; `--method`, `--interactive` and `--headful` are removed without aliases (#924).**
8
+
9
+ The two authorization domains — the Direct API OAuth token and the browser
10
+ session used by `masters`/`history` — now have explicit names:
11
+
12
+ - `direct auth login api` — OAuth login for API/v4 commands (what bare
13
+ `direct auth login` did and still does: the owner-decided default is the
14
+ API domain, and the old "Choose login method" menu is gone).
15
+ - `direct auth login browser` — manual login in a visible window for browser
16
+ commands (`masters`, `history`, ...); visibility needs no flag anymore.
17
+ `--source chrome` keeps importing an existing Chrome session headless;
18
+ `--allow-no-tty` is the only surviving special flag — it lets a script
19
+ open the login window without a terminal.
20
+ - `direct auth status api|browser` selects a domain; **bare `direct auth
21
+ status` now reports both domains** (an `API:` and a `Browser:` block,
22
+ previously the API-only default — parse the new `Browser:` section or use
23
+ `auth status api` for the old behavior; combined JSON is unchanged:
24
+ `{"api": ..., "browser": ...}`).
25
+ - `direct auth logout api --profile NAME` / `direct auth logout browser`
26
+ (bare `auth logout` asks for a domain).
27
+ - `--profile` is valid in both domains; in the browser domain it is accepted
28
+ and reported as ignored (browser sessions are shared). `--profile-dir`/
29
+ `--chrome-profile` live only in the browser domain.
30
+ - In the API domain a terminal is now the interactive default: the login
31
+ prints the URL, opens the browser, reads the code and binds the folder's
32
+ `.env`. `--format json`, `--start-pkce` and `--code -` stay headless —
33
+ unattended scripts are unaffected.
34
+
35
+ Every removed flag fails with `click.UsageError` naming the exact
36
+ replacement from `direct_cli/_auth_hints.py` — the same pointer the live
37
+ auth errors advise. Deprecated aliases (`playwright login`,
38
+ `masters login`/`logout`/`status`) keep their stdout formats; their
39
+ replacement notices now point at the new subcommand surface.
40
+
41
+ ### Added
42
+
43
+ - **Optional diagnostics output is now env-switched and hidden by default
44
+ (#925).** Successful v5 API calls no longer print anything extra: the API
45
+ Units points line is opt-in via `DIRECT_SHOW_UNITS=1`, which prints one
46
+ stderr line per successful call — `API units: <spent>/<rest>/<daily limit>`
47
+ (e.g. `API units: 10/20828/64000`), plus ` (used-login: <login>)` when the
48
+ API returned `Units-Used-Login` (agency accounts). The v4 Live API returns
49
+ no Units headers, so v4 commands stay silent under this switch. stdout is
50
+ never touched,
51
+ so pipes and `--format json` parsing are unaffected. `DIRECT_QUIET=0`
52
+ restores the legacy behaviour for channels that had one (Units had none).
53
+ Safety output — inherited-credential warnings (#909), sandbox notices, API
54
+ warnings — is never suppressed. The switch registry
55
+ (`direct_cli/optional_output.py`) is extensible: future optional channels
56
+ (Reports `retryIn`/`reportsInQueue`) are added as one entry. Supported by a
57
+ success-response hook in the vendored `tapi_yandex_direct` client, mirrored
58
+ on `master` of the axisrow fork (axisrow/tapi-yandex-direct#28, merged) so
59
+ `update_vendor.sh` keeps it (#634).
60
+
61
+ ### Changed
62
+
63
+ - **One canonical login pointer in every authorization error (#924, part 1 —
64
+ non-breaking).** A new leaf module `direct_cli/_auth_hints.py` defines the
65
+ canonical pointers — `direct auth login api`, `direct auth login browser`,
66
+ `direct auth login browser --source chrome` — and every auth error and
67
+ deprecated-command notice now advises exactly one domain-appropriate pointer.
68
+ Previously a stale `masters list` session printed four contradictory
69
+ suggestions, and a deprecated command's warning recommended different flags
70
+ than the error of the same command. Commands and flags are unchanged; the
71
+ `auth login api|browser` subcommand restructuring lands separately. An AST
72
+ guard in `tests/test_unified_auth.py` bans literal login-command strings
73
+ outside `_auth_hints.py`, so a second hint source fails CI.
74
+
75
+ ### Fixed
76
+
77
+ - **`reports get`: API error 56 (method rate limit) now retries with
78
+ exponential backoff (#918).** Yandex allows only 1 request per 10 seconds
79
+ per method; with several `direct`/MCP clients sharing one account, each
80
+ keeps consuming the other's window and the first 56 used to kill the
81
+ command (the vendored client's own retry branches read the error code from
82
+ the wrong payload key and never fire). Now the reports POST is retried up
83
+ to 5 attempts, waiting 10/20/40/80s plus up to 50% jitter; each attempt
84
+ logs `attempt N/5 … retrying in Xs` to stderr so a waiting CLI is
85
+ distinguishable from a dead one. If the limit still doesn't clear, the
86
+ final error names the likely cause — another client or session working
87
+ with the same Yandex Direct account. Any other error code (53, 152, 506,
88
+ 9000, …) fails immediately as before.
89
+ - **`reports get`: `--from`/`--to` are bound to `--date-range-type
90
+ CUSTOM_DATE` (#898).** Relative periods (`TODAY`, `YESTERDAY`, `LAST_*`,
91
+ `ALL_TIME`, `AUTO`) no longer require the flags and build requests without
92
+ `DateFrom`/`DateTo`, per the Reports spec ("required at CUSTOM_DATE and
93
+ forbidden with other values"). Explicit dates alongside a relative period,
94
+ and `CUSTOM_DATE` with either date missing, fail with a usage error instead
95
+ of silently sending a forbidden combination.
96
+ - **`--format csv`/`--format tsv`: export no longer fails when later records
97
+ carry optional fields missing from the first record (#900).** The column set
98
+ is now the union of keys across all records (in first-seen order) instead of
99
+ the first record's keys alone, so a record with an extra optional field
100
+ (e.g. `TextAd` present only on `TEXT_AD` rows) gets its own column and rows
101
+ missing a field export an empty cell — success no longer depends on row
102
+ order. Explicitly passed `headers` still define the columns exactly as
103
+ before.
104
+
105
+ - **`masters list`: intermittent grid-load timeout now retries internally
106
+ (#912).** The campaigns grid's `GridCampaigns` data request is observed
107
+ across two attempts — 30s, then 60s, with a fresh page load per attempt —
108
+ before the command fails, so an ordinary slow page load no longer surfaces
109
+ as a terminal error requiring a manual retry. The exhausted-attempts error
110
+ is worded purely as the retryable timeout it is (the old text's "Yandex may
111
+ have changed the grid's internal API" clause is gone); an unrecognized
112
+ response structure keeps its separate, API-change message. New
113
+ `masters list --timeout SECONDS` scales both per-attempt budgets for slow
114
+ connections.
115
+ - **`masters targetactions get`: a populated goals table is no longer
116
+ reported as empty (#910).** The "Целевые действия" table goes through a
117
+ genuine, non-throwing EMPTY interval mid-hydration (the same race
118
+ #750/#756 documented for the save guard), and the command answered with a
119
+ single immediate read — landing in that dip silently returned
120
+ `{"TargetActions": [], "Count": 0}` for a campaign whose table is
121
+ populated, indistinguishable from genuinely empty (the audit over 28
122
+ campaigns produced 2 false violations this way). The read is now the same
123
+ settled, failure-aware snapshot the `--preserve-target-actions` guard
124
+ uses: rows are reported only once their `{GoalId: Price}` identity is
125
+ stable, and a rendered section whose rows never settle into a readable
126
+ snapshot fails with an error instead of printing `Count: 0`. A genuinely
127
+ empty table still answers `Count: 0`, and so does a max-clicks campaign
128
+ (no section rendered) — the latter now pays the settle deadline (~20 s)
129
+ before that answer, same as the guard path, because the same dips briefly
130
+ unmount the section and its absence is only meaningful after settling had
131
+ its chance.
132
+
133
+ ## 0.5.4 — 2026-10-24
134
+
135
+ ### Unified authorization
136
+
137
+ - **Existing profiles are never overwritten silently.** `direct auth login`
138
+ refuses to write credentials into an existing profile (including the default
139
+ `default`) without explicit `--force`; a fresh profile name is unaffected.
140
+ Previously a headless completion replaced the profile's token, refresh token
141
+ and OAuth client without warning. The refusal names the current owner's
142
+ login, and replacing an existing `YANDEX_DIRECT_TOKEN` in the folder `.env`
143
+ prints a warning.
144
+ - Authorization is headless and non-interactive by default, including in a
145
+ terminal. Login dialogs require `--interactive`; manual browser login also
146
+ accepts explicit `--headful`. TTY detection never selects an interactive mode.
147
+ - Chrome import no longer retries failed headless verification with a visible
148
+ browser. Legacy browser login paths also require an explicit UI flag.
149
+
150
+ - Canonical API/browser login, status, logout and browser diagnostics now live
151
+ under `direct auth`. Existing explicit login paths and JSON remain supported
152
+ through deprecated adapters; credentials and browser storage are not migrated.
153
+ - Resource commands use saved browser sessions only. Missing, expired or rejected
154
+ sessions fail with a login hint, without Chrome cookie import, Keychain access
155
+ or retrying an operation. Move resource Chrome flags to explicit
156
+ `direct auth login --method browser --source chrome`.
157
+ - API logout removes the selected local profile and this folder's binding;
158
+ browser logout removes both CLI browser sessions. Source Chrome is untouched.
159
+ - Browser diagnostics skip Keychain and cookie decryption, preserving check names.
160
+
161
+ ### BREAKING CHANGES
162
+
163
+ **A folder with no bound credentials has no credentials — the global active
164
+ profile is no longer inherited silently (#904).**
165
+
166
+ Since #489 a folder with no explicit credential binding (no cwd `.env`, no
167
+ `--profile`, no base env) silently resolved credentials from the global
168
+ active profile in `~/.direct-cli/auth.json` — every new project started
169
+ billing the last logged-in account, and `direct auth status` reported an
170
+ indistinguishable `source=oauth`. Now an unbound folder has no credentials:
171
+
172
+ - **Non-interactive sessions** (scripts, sub-processes — including the
173
+ Yandex Direct MCP plugin): every API command fails with `UsageError` and
174
+ binding hints until the folder is bound. New: `direct auth write --profile
175
+ <name>` binds a folder without any prompts — it writes the profile's
176
+ credentials to the cwd `.env` (merge, `0600`, the token is never printed);
177
+ `--profile` is required, nothing is bound implicitly.
178
+ - **Terminal sessions** also fail without opening a login dialog. Explicit
179
+ `direct auth login --interactive` offers API or browser authorization. The API menu
180
+ binds a saved or newly authorized profile to the cwd `.env` immediately;
181
+ a newly named profile does not change the global active profile.
182
+ `--dry-run` still needs no credentials and stays silent.
183
+ - **`direct auth status`** in an unbound folder reports
184
+ `source=null`/`has_token=false` plus a note about the global profile
185
+ (`global_profile`/`global_login` in JSON) — the global profile exists, but
186
+ it is not presented as this folder's credentials.
187
+ - **Opt-in**: `YANDEX_DIRECT_INHERIT_GLOBAL=1` restores the #489 behavior —
188
+ the global active profile is inherited silently again, and `auth status`
189
+ labels it `source=global-profile-inherited`.
190
+
191
+ Explicit bindings are unchanged and still win: `--token`, `--profile`,
192
+ base env, cwd `.env`. `--sandbox` does not bypass the gate — the sandbox
193
+ authenticates under the same profile login, so a wrong inherited account is
194
+ the same mistake there. A folder with only a partial credential ref (e.g.
195
+ an exported `YANDEX_DIRECT_LOGIN` and no token) no longer silently inherits
196
+ the global active profile either — the bind gate applies there too.
197
+
198
+ Migration: bind the folders you use via a `.env` file (`direct auth write`,
199
+ or run `direct auth login --method api` once per folder), pass `--profile`, or set
200
+ `YANDEX_DIRECT_INHERIT_GLOBAL=1` where inheritance is intended.
201
+
202
+ Offline tests are insulated from the same nondeterminism: the suite now
203
+ points `AUTH_STORE_PATH` at a per-test file by default (autouse fixture;
204
+ live tiers keep the real store so their profile fallback still works) and
205
+ runs under the inheritance opt-in, so offline tests no longer change
206
+ behavior with the developer's active `direct auth` profile. The `ruff` dev
207
+ pin moves to `>=0.16,<0.17` with the pre-0.16 default rule set pinned
208
+ explicitly in `[tool.ruff.lint] select`, so lint behavior no longer drifts
209
+ with the ruff version.
210
+
3
211
  ## 0.5.3 — 2026-10-07
4
212
 
5
213
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: direct-cli
3
- Version: 0.5.3
3
+ Version: 0.5.4
4
4
  Summary: Command-line interface for Yandex Direct API
5
5
  Author: axisrow
6
6
  License: MIT
@@ -37,7 +37,7 @@ Requires-Dist: black>=22.0; extra == "dev"
37
37
  Requires-Dist: flake8>=4.0; extra == "dev"
38
38
  Requires-Dist: mypy>=1.8; extra == "dev"
39
39
  Requires-Dist: pyright>=1.1.400; extra == "dev"
40
- Requires-Dist: ruff<0.16,>=0.1; extra == "dev"
40
+ Requires-Dist: ruff<0.17,>=0.16; extra == "dev"
41
41
  Requires-Dist: requests>=2.0; extra == "dev"
42
42
  Requires-Dist: beautifulsoup4>=4.12; extra == "dev"
43
43
  Requires-Dist: lxml>=4.9; extra == "dev"
@@ -66,18 +66,16 @@ pip install direct-cli
66
66
  Мастер кампаний has **no Yandex Direct API surface at all** — it only exists
67
67
  in the web interface, and must not be confused with `UNIFIED_CAMPAIGN` (an
68
68
  unrelated v5 API campaign type already supported by `campaigns add/get --type
69
- unified_campaign`). `direct masters list` / `direct masters get <ids>` read it
70
- by decrypting your existing Chrome cookies for `yandex.ru` and injecting them
71
- into a Playwright-driven browser — no separate login. Only those cookies are
72
- ever read; the rest of your Chrome profile is never touched. On macOS the
73
- cookie key lives in your login Keychain, so the first run shows a one-time
74
- system permission dialog — click Allow. Linux is supported when Chrome uses
75
- its basic (non-keyring) password store; Windows isn't supported yet. Requires
76
- the optional `browser` extra:
69
+ unified_campaign`). Browser-backed commands use a saved browser session,
70
+ independent of the API token. Set it up explicitly with
71
+ `direct auth login browser`. This opens a CLI-owned Chromium window
72
+ and works on macOS/Linux/Windows without reading Chrome or Keychain.
73
+ Requires the optional `browser` extra:
77
74
 
78
75
  ```bash
79
76
  pip install "direct-cli[browser]"
80
77
  playwright install chromium
78
+ direct auth login browser
81
79
  direct masters list
82
80
  direct masters list --status archived
83
81
  direct masters get 72349978
@@ -245,18 +243,18 @@ never a silent skip, and the whole plan (including that local image/video
245
243
  files exist) is validated before the first save.
246
244
 
247
245
  A campaign that fails is reported with an `Error` and does not stop the rest;
248
- the command exits non-zero afterwards. If the browser session goes stale
249
- mid-plan it is re-opened once and the run continues from the first campaign
250
- that was never saved — an already-saved campaign is never saved twice.
246
+ the command exits non-zero afterwards. If browser authorization fails mid-plan,
247
+ the run stops with a login hint. It never imports cookies or repeats the
248
+ operation under another session.
251
249
  `--pacing-ms` (default 1000) controls the pause between campaigns,
252
250
  `--moderation-statuses` additionally reads each campaign's current moderation
253
251
  statuses after its save (a snapshot — moderation usually has not run yet at
254
252
  that point, so a rejection can still appear later), and `--dry-run` prints
255
253
  what would be applied without opening a browser.
256
254
 
257
- If you see "Found no Yandex cookies", open https://direct.yandex.ru in Chrome
258
- and log in first. If you use a non-default Chrome profile, pass
259
- `--chrome-profile "Profile 1"`.
255
+ To import an existing Chrome session instead, run
256
+ `direct auth login browser --source chrome --chrome-profile "Profile 1"`.
257
+ Chrome profile flags belong to explicit login, not resource commands.
260
258
 
261
259
  Since this data has no API contract, the parser degrades per-section (a
262
260
  warning, not a hard failure) if Yandex changes the page markup, rather than
@@ -334,33 +332,26 @@ running it twice creates a SECOND copy, not an update to the first. By
334
332
  default the copy is saved as a draft (`--draft`); pass `--launch` to launch
335
333
  it immediately in production instead. Same no-`--sandbox` caveat as `add`.
336
334
 
337
- **Browser session (optional but recommended):** `direct masters` decrypts
338
- your Chrome cookies fresh on every call by default, which means a Keychain
339
- prompt every time on macOS. Run `direct playwright login` once to decrypt
340
- and save a reusable session (`~/.direct-cli/playwright/session.json`, `0600`)
341
- — subsequent `direct masters` calls use it automatically and skip the
342
- Keychain round-trip. If something in the pipeline is broken (playwright not
343
- installed, wrong Chrome profile, expired session), `direct playwright
344
- doctor` reports the full chain of checks without logging in or writing
345
- anything.
346
-
347
- **Keychain-free alternative:** `direct masters login` opens a visible
348
- browser window on a persistent Chromium profile owned by the CLI
349
- (`~/.direct-cli/chrome-profile/`) — log in by hand once via Yandex Passport,
350
- and the command exits once the session is confirmed. This never touches your
351
- real Chrome profile or the macOS Keychain at all, so it works identically on
352
- macOS/Linux/Windows; the cost is a one-time manual login instead of a
353
- transparent cookie copy. When this profile exists, `direct masters` prefers
354
- it automatically over the saved `playwright login` session. It's interactive
355
- (blocks for up to `--timeout` seconds, default 300, waiting for you to sign
356
- in), so it can't run unattended. Run `direct masters logout` to delete the
357
- profile and revoke the on-disk session (a no-op warning, not an error, if
358
- none exists).
359
-
360
- Run `direct masters status` to check which of these two sessions `masters`
361
- commands would currently use — which tier is active, the persistent
362
- profile's path, and the saved session's expiry — without any network call
363
- or side effect (no browser launch, unlike every other `masters` command).
335
+ **Browser authorization:** `direct auth login browser` opens the
336
+ CLI's persistent Chromium profile (`~/.direct-cli/chrome-profile/`) and waits
337
+ up to `--timeout` seconds (default 300) for manual login. It requires a
338
+ terminal unless `--allow-no-tty` is explicitly supplied.
339
+
340
+ Alternatively, `direct auth login browser --source chrome` imports
341
+ Chrome cookies into `~/.direct-cli/playwright/session.json` (`0600`). Only
342
+ this explicit import may request Keychain access. `--profile-dir` selects the
343
+ source directory and `--chrome-profile` the Chrome profile subdirectory.
344
+
345
+ Commands prefer an existing persistent Chromium session over an imported
346
+ session. `direct auth status browser` inspects both without opening
347
+ a browser; it reports saved state, not proof of current server-side validity.
348
+ `direct auth doctor` diagnoses dependencies and saved session metadata;
349
+ cookie decryption checks are skipped. Missing or rejected sessions produce
350
+ a login hint; commands never start login or import cookies automatically.
351
+
352
+ `direct auth logout browser` removes both CLI-owned browser sessions.
353
+ It does not touch the original Chrome profile. Old browser-auth commands
354
+ remain deprecated compatibility aliases; their stdout formats are preserved.
364
355
 
365
356
  ### История изменений (change history) — browser-only
366
357
 
@@ -370,8 +361,8 @@ changed IDs, and Live v4's `GetEventsLog` logs *system* events
370
361
  (`BannerModerated`, `MoneyOut`, …) — none of them can answer "who changed
371
362
  this field, when, and from what to what". That history exists only in the web
372
363
  interface's «История изменений» section, so `direct history` reads it through
373
- the same browser session `direct masters` uses (same `--headful`/
374
- `--profile-dir`/`--chrome-profile` options, same no-`--login` rule):
364
+ the same saved browser session `direct masters` uses (same `--headful`
365
+ option and no-`--login` rule):
375
366
 
376
367
  ```bash
377
368
  direct history get
@@ -399,6 +390,63 @@ A bare `--date-from`/`--date-to` date covers the whole day; pass
399
390
  `YYYY-MM-DDTHH:MM:SS` for an exact window. Without them, the period the
400
391
  section itself defaults to is used.
401
392
 
393
+ ### Authorization
394
+
395
+ `auth login` has two explicit domains: `direct auth login api` (an OAuth
396
+ token for API/v4 commands, saved in an auth profile) and
397
+ `direct auth login browser` (a browser session for browser commands:
398
+ `masters`, `history`, ...). Bare `direct auth login` is the API login.
399
+
400
+ In a terminal the API login is interactive by default: it prints the
401
+ authorize URL, opens the browser, reads the code, and binds the credentials
402
+ to this folder's `.env`. In a non-interactive shell it prints the API
403
+ authorization URL without opening a browser or asking questions. Complete
404
+ the two-step flow with `--code` or `--code -` and bind a saved profile with
405
+ `direct auth write --profile NAME`. Saving into an existing profile
406
+ (including the default `default`) requires explicit `--force`; without it
407
+ the save refuses to overwrite stored credentials. The CLI never replaces
408
+ stored credentials, profiles or browser sessions silently: a replacement is
409
+ either the command's declared purpose (and it reports what was replaced) or
410
+ requires explicit `--force`.
411
+
412
+ The API login in a terminal first offers to reuse a saved profile (bound to
413
+ this folder's `.env` on the spot); otherwise a new profile name comes from
414
+ the account login and gets a numeric suffix when the name is taken.
415
+ API credentials and browser cookies stay separate and may belong to
416
+ different accounts.
417
+
418
+ ```bash
419
+ direct auth login # = direct auth login api
420
+ direct auth login api
421
+ direct auth login browser # manual login in a visible window
422
+ direct auth login browser --source chrome
423
+ direct auth status # both domains
424
+ direct auth status api
425
+ direct auth status browser
426
+ direct auth doctor
427
+ direct auth logout api --profile agency1
428
+ direct auth logout browser
429
+ ```
430
+
431
+ Manual browser login is visible by definition; `--allow-no-tty` only
432
+ overrides the terminal check for scripts that open the window on purpose.
433
+ Chrome import stays headless, including when verification fails: there is no
434
+ automatic headful retry. All resource commands fail with
435
+ a helpful error when authorization is missing, including in a terminal.
436
+ `direct` without arguments still shows help. API logout removes the named
437
+ local profile and this folder's API binding, preserving other `.env` settings.
438
+ The binding includes local token/login values, secret-manager references and
439
+ the folder's global-profile inheritance setting.
440
+ It does not revoke token copies in other folders, external environments, or
441
+ secret managers. Browser logout removes both saved CLI sessions.
442
+
443
+ `auth status` reports both domains (an `API:` and a `Browser:` block);
444
+ combined JSON has `api` and `browser` sections. `auth status api` and
445
+ `auth status browser` select one domain. Existing API flags and two-step
446
+ PKCE/stdin login remain supported in unattended workflows. The old
447
+ `--method`/`--interactive`/`--headful` flags were removed without aliases:
448
+ each old form fails with the exact replacement command.
449
+
402
450
  ### Configuration
403
451
 
404
452
  Create a `.env` file in your working directory:
@@ -446,11 +494,12 @@ Notes:
446
494
  - In a non-interactive shell, run `direct auth login --profile NAME` first, then finish with `direct auth login --code - --profile NAME` and pass the browser code on stdin.
447
495
  - `direct auth login --code CODE --profile NAME` remains supported for compatibility, but automation should use `--code -` to avoid exposing the code in process arguments.
448
496
  - If the first non-interactive step includes `--client-secret`, the secret is remembered for the matching completion step.
449
- - If a profile already stores a confidential OAuth client, `direct auth login --code CODE --profile NAME` reuses the saved `client_id` and `client_secret`.
497
+ - If a profile already stores a confidential OAuth client, `direct auth login --code CODE --profile NAME` reuses the saved `client_id` and `client_secret`. Re-logging into an existing profile requires `--force`.
450
498
  - `direct auth login --oauth-token TOKEN` is a manual access-token import and does not auto-refresh.
451
- - After a successful interactive login, Direct CLI asks whether to save the
452
- access token and login to the current working directory `.env`; non-interactive
453
- login flows do not prompt.
499
+ - In a terminal, the interactive API login saves the selected API profile
500
+ directly to the current folder's `.env`. Headless flows never ask for save
501
+ confirmation; use `direct auth write --profile NAME` to bind the folder
502
+ explicitly.
454
503
  - Alias `auth_login` is not supported.
455
504
 
456
505
  Credential resolution priority:
@@ -474,6 +523,44 @@ base `YANDEX_DIRECT_LOGIN`; this prevents mixing accounts. `direct auth status`
474
523
  without `--profile` reports the effective credential source; with `--profile` it
475
524
  reports that profile.
476
525
 
526
+ **An unbound folder has no credentials (#904).** When credentials would come
527
+ from the active profile fallback (priority 4) — e.g. a brand-new folder with
528
+ no `.env` — the CLI no longer inherits them silently:
529
+
530
+ - Non-interactive sessions (scripts, sub-processes): API commands fail with
531
+ `UsageError` and binding hints until the folder is bound. Bind a folder
532
+ without prompts via `direct auth write --profile <name>` — it writes the
533
+ profile's credentials to the cwd `.env` (merge, `0600`, token never
534
+ printed); `--profile` is required, nothing is bound implicitly.
535
+ - Terminal sessions follow the same rule: an ordinary command never opens a
536
+ login dialog. Run `direct auth login api` to choose or
537
+ authorize a profile and bind it to this folder. A profile created through
538
+ the menu does not change the global active profile.
539
+ - `direct auth status` in an unbound folder reports
540
+ `source=null`/`has_token=false` and notes the global profile
541
+ (`global_profile`/`global_login` in JSON) without presenting it as this
542
+ folder's credentials.
543
+ - `--dry-run` needs no credentials and stays silent; `--sandbox` does not
544
+ bypass the gate — the sandbox authenticates under the same profile login.
545
+ - Set `YANDEX_DIRECT_INHERIT_GLOBAL=1` to restore the former silent
546
+ inheritance for unattended workflows (auth status then labels it
547
+ `source=global-profile-inherited`).
548
+
549
+ ### Optional diagnostics output (#925)
550
+
551
+ Optional output — data you did not ask for — is hidden by default and printed
552
+ to stderr only, so stdout stays byte-identical for pipes and JSON parsing:
553
+
554
+ | Env var | Effect |
555
+ |---------|--------|
556
+ | `DIRECT_SHOW_UNITS=1` | After each successful v5 API call, one stderr line with the API Units points: `API units: <spent>/<rest>/<daily limit>` (e.g. `API units: 10/20828/64000`), plus ` (used-login: <login>)` for agency accounts (`Units-Used-Login`). The v4 Live API returns no Units headers, so v4 commands (`direct balance`, …) stay silent under this switch |
557
+ | `DIRECT_QUIET=0` | Master switch back to the legacy behaviour for optional output that existed before #925 (Units had none) |
558
+
559
+ `DIRECT_SHOW_UNITS=1` works even with `DIRECT_QUIET=1`; an explicit
560
+ `DIRECT_SHOW_UNITS=0` wins over `DIRECT_QUIET=0`. Safety output — inherited
561
+ credential warnings (#909), sandbox notices, API warnings — is never
562
+ suppressed. Limit errors already include Units in their text (#921).
563
+
477
564
  > **Tests follow the safe credential order.** Live-API test suites (e.g. `tests/test_v4_live_contracts.py`) read `YANDEX_DIRECT_TOKEN` / `YANDEX_DIRECT_LOGIN` from the environment first, only then fall back to the active `direct auth` profile, and skip the test if neither is set. This prevents a developer machine with an active profile from silently hitting production on a plain `pytest` invocation. See `CLAUDE.md` for the contract.
478
565
 
479
566
  Install with `pip install direct-cli`, then run commands with `direct`.
@@ -1065,6 +1152,15 @@ direct dictionaries get-retargeting-goals --ids 19000000660,19000001592
1065
1152
  > more than one goal `Type` (e.g. `HOST` and `APPLICATION`) for similar names
1066
1153
  > — pick the entry with the `Type` your use case needs.
1067
1154
 
1155
+ > `retargeting get` returns each list's `Scope` (a default field):
1156
+ > `FOR_TARGETS_ONLY` / `FOR_TARGETS_AND_ADJUSTMENTS` /
1157
+ > `FOR_ADJUSTMENTS_ONLY`. There is no `--scope` flag: the WSDL declares
1158
+ > `Scope` only on `RetargetingListGetItem`, so the API assigns it
1159
+ > server-side. Verified live (#890): `retargeting get` returns
1160
+ > every documented scope class present in the account — an empty
1161
+ > adjustment-class section means the account has no such lists, not
1162
+ > server-side filtering.
1163
+
1068
1164
  ```bash
1069
1165
  # Bids and modifiers
1070
1166
  direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
@@ -1076,6 +1172,10 @@ direct keywordbids set-auto --keyword-id 321 --target-traffic-volume 100 --incre
1076
1172
  direct bidmodifiers get --campaign-ids 123 --fields Id,CampaignId,AdGroupId,Level,Type
1077
1173
  direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
1078
1174
  direct bidmodifiers add --campaign-id 123 --type MOBILE_ADJUSTMENT --value 120 --operating-system-type IOS --dry-run
1175
+ # RETARGETING_SEARCH_ADJUSTMENT is a live-only type (#871): the payload is
1176
+ # mirrored, but Yandex currently rejects its creation with 5005 on every
1177
+ # documented retargeting-list class (#890) — works once acceptance is enabled.
1178
+ direct bidmodifiers add --campaign-id 123 --type RETARGETING_SEARCH_ADJUSTMENT --retargeting-condition-id 12345 --value 120 --dry-run
1079
1179
  direct bidmodifiers set --id 99 --value 130 --dry-run
1080
1180
 
1081
1181
  # Canonical multiword groups