direct-cli 0.3.4__tar.gz → 0.3.6__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 (214) hide show
  1. {direct_cli-0.3.4 → direct_cli-0.3.6}/PKG-INFO +59 -57
  2. {direct_cli-0.3.4 → direct_cli-0.3.6}/README.md +58 -56
  3. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/auth.py +98 -1
  4. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/cli.py +2 -5
  5. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/audiencetargets.py +5 -2
  6. direct_cli-0.3.6/direct_cli/commands/auth.py +432 -0
  7. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/bidmodifiers.py +3 -20
  8. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/campaigns.py +106 -1
  9. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/dictionaries.py +3 -5
  10. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/dynamicads.py +5 -2
  11. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/dynamicfeedadtargets.py +1 -3
  12. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/strategies.py +154 -34
  13. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/v4account.py +78 -15
  14. direct_cli-0.3.6/direct_cli/commands/v4wordstat.py +157 -0
  15. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/smoke_matrix.py +6 -2
  16. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/v4_contracts.py +37 -16
  17. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli.egg-info/PKG-INFO +59 -57
  18. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli.egg-info/SOURCES.txt +4 -0
  19. {direct_cli-0.3.4 → direct_cli-0.3.6}/pyproject.toml +1 -1
  20. {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/sandbox_write_live.py +122 -0
  21. {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/test_safe_commands.sh +6 -0
  22. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/api_coverage_payloads.py +4 -0
  23. direct_cli-0.3.6/tests/test_auth_oauth.py +1495 -0
  24. direct_cli-0.3.6/tests/test_cli_contract.py +192 -0
  25. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_dry_run.py +149 -3
  26. direct_cli-0.3.6/tests/test_low_coverage_payloads.py +853 -0
  27. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_smoke_matrix.py +153 -3
  28. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4_safety.py +4 -4
  29. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4account.py +109 -3
  30. direct_cli-0.3.6/tests/test_v4wordstat.py +250 -0
  31. direct_cli-0.3.4/direct_cli/commands/auth.py +0 -202
  32. direct_cli-0.3.4/tests/test_auth_oauth.py +0 -703
  33. {direct_cli-0.3.4 → direct_cli-0.3.6}/.env.example +0 -0
  34. {direct_cli-0.3.4 → direct_cli-0.3.6}/.github/copilot-instructions.md +0 -0
  35. {direct_cli-0.3.4 → direct_cli-0.3.6}/.github/workflows/api-coverage.yml +0 -0
  36. {direct_cli-0.3.4 → direct_cli-0.3.6}/.github/workflows/claude-code-review.yml +0 -0
  37. {direct_cli-0.3.4 → direct_cli-0.3.6}/.github/workflows/claude.yml +0 -0
  38. {direct_cli-0.3.4 → direct_cli-0.3.6}/.github/workflows/quality.yml +0 -0
  39. {direct_cli-0.3.4 → direct_cli-0.3.6}/.gitignore +0 -0
  40. {direct_cli-0.3.4 → direct_cli-0.3.6}/AGENTS.md +0 -0
  41. {direct_cli-0.3.4 → direct_cli-0.3.6}/CHANGELOG.md +0 -0
  42. {direct_cli-0.3.4 → direct_cli-0.3.6}/CLAUDE.md +0 -0
  43. {direct_cli-0.3.4 → direct_cli-0.3.6}/MANIFEST.in +0 -0
  44. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/__init__.py +0 -0
  45. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_deprecated.py +0 -0
  46. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_smoke_probes.py +0 -0
  47. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/__init__.py +0 -0
  48. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/__init__.py +0 -0
  49. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/endpoints.py +0 -0
  50. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/exceptions.py +0 -0
  51. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/resource_mapping.py +0 -0
  52. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.py +0 -0
  53. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.pyi +0 -0
  54. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/v4/__init__.py +0 -0
  55. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.py +0 -0
  56. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.pyi +0 -0
  57. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/v4/resource_mapping.py +0 -0
  58. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/api.py +0 -0
  59. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/__init__.py +0 -0
  60. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/adextensions.py +0 -0
  61. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/adgroups.py +0 -0
  62. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/adimages.py +0 -0
  63. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/ads.py +0 -0
  64. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/advideos.py +0 -0
  65. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/agencyclients.py +0 -0
  66. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/balance.py +0 -0
  67. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/bids.py +0 -0
  68. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/businesses.py +0 -0
  69. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/changes.py +0 -0
  70. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/clients.py +0 -0
  71. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/creatives.py +0 -0
  72. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/feeds.py +0 -0
  73. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/keywordbids.py +0 -0
  74. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/keywords.py +0 -0
  75. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/keywordsresearch.py +0 -0
  76. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/leads.py +0 -0
  77. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/negativekeywordsharedsets.py +0 -0
  78. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/reports.py +0 -0
  79. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/retargeting.py +0 -0
  80. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/sitelinks.py +0 -0
  81. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/smartadtargets.py +0 -0
  82. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/turbopages.py +0 -0
  83. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/v4events.py +0 -0
  84. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/v4finance.py +0 -0
  85. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/v4goals.py +0 -0
  86. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/v4shells.py +0 -0
  87. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/vcards.py +0 -0
  88. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/output.py +0 -0
  89. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/reports_coverage.py +0 -0
  90. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/utils.py +0 -0
  91. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/v4/__init__.py +0 -0
  92. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/v4/money.py +0 -0
  93. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/wsdl_coverage.py +0 -0
  94. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli.egg-info/dependency_links.txt +0 -0
  95. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli.egg-info/entry_points.txt +0 -0
  96. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli.egg-info/requires.txt +0 -0
  97. {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli.egg-info/top_level.txt +0 -0
  98. {direct_cli-0.3.4 → direct_cli-0.3.6}/docs/superpowers/plans/2026-04-12-issue-32-completion.md +0 -0
  99. {direct_cli-0.3.4 → direct_cli-0.3.6}/docs/superpowers/specs/2026-04-23-vendor-tapi-yandex-direct-design.md +0 -0
  100. {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/anonymize_cassettes.py +0 -0
  101. {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/build_api_coverage_checklist.py +0 -0
  102. {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/build_api_coverage_report.py +0 -0
  103. {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/check_reports_drift.py +0 -0
  104. {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/check_wsdl_drift.py +0 -0
  105. {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/patch_vendor_imports.py +0 -0
  106. {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/refresh_reports_cache.py +0 -0
  107. {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/refresh_wsdl_cache.py +0 -0
  108. {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/release_pypi.sh +0 -0
  109. {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/test_dangerous_commands.sh +0 -0
  110. {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/test_sandbox_write.sh +0 -0
  111. {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/update_vendor.sh +0 -0
  112. {direct_cli-0.3.4 → direct_cli-0.3.6}/setup.cfg +0 -0
  113. {direct_cli-0.3.4 → direct_cli-0.3.6}/setup.py +0 -0
  114. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/API_COVERAGE.md +0 -0
  115. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/API_ISSUE_AUDIT.md +0 -0
  116. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/MANUAL_COVERAGE.md +0 -0
  117. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/__init__.py +0 -0
  118. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_adgroups_add_update_delete.yaml +0 -0
  119. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_adimages_add_get_delete.yaml +0 -0
  120. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_ads_add_update_delete.yaml +0 -0
  121. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_ads_suspend_resume_archive_unarchive.yaml +0 -0
  122. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_advideos_add_get.yaml +0 -0
  123. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_add_delete.yaml +0 -0
  124. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_suspend_resume.yaml +0 -0
  125. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_bids_set.yaml +0 -0
  126. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_campaign_create_get_delete.yaml +0 -0
  127. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_creatives_chain_advideo_to_creative.yaml +0 -0
  128. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_add_delete.yaml +0 -0
  129. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_suspend_resume.yaml +0 -0
  130. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_keywordbids_set.yaml +0 -0
  131. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_keywords_add_update_delete.yaml +0 -0
  132. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_keywords_suspend_resume.yaml +0 -0
  133. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_sitelinks_add_get_delete.yaml +0 -0
  134. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_add_update_delete.yaml +0 -0
  135. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_suspend_resume.yaml +0 -0
  136. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yaml +0 -0
  137. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteAdGroups.test_add_update_delete.yaml +0 -0
  138. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteAdImages.test_add_delete.yaml +0 -0
  139. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteAds.test_add_text_ad_update_delete.yaml +0 -0
  140. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteAudienceTargets.test_add_delete.yaml +0 -0
  141. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteBidModifiersAdd.test_add_delete_mobile.yaml +0 -0
  142. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteBidModifiersSet.test_set_without_id_is_rejected.yaml +0 -0
  143. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteBids.test_set_bid.yaml +0 -0
  144. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteCampaignDraftLifecycle.test_draft_create_get_delete.yaml +0 -0
  145. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteCampaigns.test_campaign_lifecycle.yaml +0 -0
  146. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yaml +0 -0
  147. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yaml +0 -0
  148. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteKeywordBids.test_set_keyword_bid.yaml +0 -0
  149. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteKeywords.test_add_update_delete.yaml +0 -0
  150. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteNegativeKeywordSharedSets.test_add_update_delete.yaml +0 -0
  151. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yaml +0 -0
  152. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteSitelinks.test_add_delete.yaml +0 -0
  153. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml +0 -0
  154. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteVCards.test_add_delete.yaml +0 -0
  155. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/conftest.py +0 -0
  156. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/fixtures/test-video.mp4 +0 -0
  157. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/reports_cache/raw/fields-list.html +0 -0
  158. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/reports_cache/raw/headers.html +0 -0
  159. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/reports_cache/raw/period.html +0 -0
  160. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/reports_cache/raw/spec.html +0 -0
  161. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/reports_cache/raw/type.html +0 -0
  162. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/reports_cache/spec.json +0 -0
  163. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_api_coverage.py +0 -0
  164. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_auth_bw.py +0 -0
  165. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_auth_op.py +0 -0
  166. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_balance.py +0 -0
  167. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_cli.py +0 -0
  168. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_comprehensive.py +0 -0
  169. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_integration.py +0 -0
  170. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_integration_live_write.py +0 -0
  171. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_integration_write.py +0 -0
  172. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_reports_drift.py +0 -0
  173. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_reports_parsing.py +0 -0
  174. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_transport_contract.py +0 -0
  175. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4_contracts.py +0 -0
  176. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4_foundation.py +0 -0
  177. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4_live_contracts.py +0 -0
  178. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4events.py +0 -0
  179. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4finance_money.py +0 -0
  180. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4finance_read.py +0 -0
  181. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4goals.py +0 -0
  182. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_vendor_imports.py +0 -0
  183. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/adextensions.xml +0 -0
  184. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/adgroups.xml +0 -0
  185. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/adimages.xml +0 -0
  186. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/ads.xml +0 -0
  187. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/advideos.xml +0 -0
  188. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/agencyclients.xml +0 -0
  189. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/audiencetargets.xml +0 -0
  190. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/bidmodifiers.xml +0 -0
  191. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/bids.xml +0 -0
  192. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/businesses.xml +0 -0
  193. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/campaigns.xml +0 -0
  194. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/changes.xml +0 -0
  195. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/clients.xml +0 -0
  196. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/creatives.xml +0 -0
  197. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/dictionaries.xml +0 -0
  198. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/dynamicfeedadtargets.xml +0 -0
  199. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/dynamictextadtargets.xml +0 -0
  200. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/feeds.xml +0 -0
  201. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/imports/adextensiontypes.xsd +0 -0
  202. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/imports/general.xsd +0 -0
  203. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/imports/generalclients.xsd +0 -0
  204. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/keywordbids.xml +0 -0
  205. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/keywords.xml +0 -0
  206. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/keywordsresearch.xml +0 -0
  207. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/leads.xml +0 -0
  208. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/negativekeywordsharedsets.xml +0 -0
  209. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/retargetinglists.xml +0 -0
  210. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/sitelinks.xml +0 -0
  211. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/smartadtargets.xml +0 -0
  212. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/strategies.xml +0 -0
  213. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/turbopages.xml +0 -0
  214. {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/vcards.xml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: direct-cli
3
- Version: 0.3.4
3
+ Version: 0.3.6
4
4
  Summary: Command-line interface for Yandex Direct API
5
5
  Author: axisrow
6
6
  License: MIT
@@ -86,7 +86,9 @@ OAuth and profile commands:
86
86
  ```bash
87
87
  direct auth login
88
88
  direct auth login --profile agency1
89
+ direct auth login --profile agency1 --format json
89
90
  direct auth login --code abc123 --profile agency1
91
+ printf '%s\n' abc123 | direct auth login --code - --profile agency1
90
92
  direct auth list
91
93
  direct auth use --profile agency1
92
94
  direct auth status --profile agency1
@@ -99,6 +101,10 @@ Notes:
99
101
  - `--login` remains Direct client login.
100
102
  - Authorization is performed via `direct auth login`.
101
103
  - OAuth profiles store refresh tokens and refresh access tokens automatically.
104
+ - 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.
105
+ - `direct auth login --code CODE --profile NAME` remains supported for compatibility, but automation should use `--code -` to avoid exposing the code in process arguments.
106
+ - If the first non-interactive step includes `--client-secret`, the secret is remembered for the matching completion step.
107
+ - If a profile already stores a confidential OAuth client, `direct auth login --code CODE --profile NAME` reuses the saved `client_id` and `client_secret`.
102
108
  - `direct auth login --oauth-token TOKEN` is a manual access-token import and does not auto-refresh.
103
109
  - Alias `auth_login` is not supported.
104
110
 
@@ -159,6 +165,19 @@ direct v4events get-events-log --from 2026-04-14T00:00:00 --to 2026-04-15T00:00:
159
165
  direct v4events get-events-log --from 2026-04-14T00:00:00 --to 2026-04-15T00:00:00 --currency RUB --limit 100 --offset 0 --format table
160
166
  ```
161
167
 
168
+ ### V4 Live Wordstat Reports
169
+
170
+ Wordstat reports are asynchronous. Direct CLI makes exactly one API call per
171
+ command and does not poll automatically; repeat `list-reports` or `get-report`
172
+ yourself until the report is ready.
173
+
174
+ ```bash
175
+ direct v4wordstat create-report --phrases "buy laptop,buy desktop" --geo-ids 213
176
+ direct v4wordstat list-reports --format table
177
+ direct v4wordstat get-report --report-id 123 --format table
178
+ direct v4wordstat delete-report --report-id 123
179
+ ```
180
+
162
181
  ### V4 Live Finance
163
182
 
164
183
  Finance methods require an extra financial token for money operations. In the
@@ -186,14 +205,15 @@ direct v4finance pay-campaigns --campaign-ids 123,456 --amount 100.50 --currency
186
205
 
187
206
  ### V4 Live Shared Account
188
207
 
189
- Shared-account mutations are dry-run-only in this release and always require
190
- `--dry-run`. These commands follow the official v4 Live shared-account method
191
- shapes: `EnableSharedAccount` accepts one client `Login`, and
192
- `AccountManagement` updates shared-account settings through `Accounts`.
208
+ Shared-account mutations require `--dry-run` in production and can be sent live
209
+ only with top-level `--sandbox`. These commands follow the official v4 Live
210
+ shared-account method shapes: `EnableSharedAccount` accepts one client `Login`,
211
+ and `AccountManagement` updates shared-account settings through `Accounts`.
193
212
 
194
213
  ```bash
195
214
  direct v4account enable-shared-account --client-login client-login --dry-run
196
215
  direct v4account account-management --action Update --account-id 1327944 --day-budget 100.50 --spend-mode Default --money-in-sms Yes --money-out-sms No --email ops@example.com --money-warning-value 25 --dry-run
216
+ direct --sandbox v4account enable-shared-account --client-login client-login
197
217
  ```
198
218
 
199
219
  ### CLI Convention
@@ -263,13 +283,8 @@ Allowed:
263
283
  direct dictionaries get-geo-regions --region-ids 225,187 --fields GeoRegionId,GeoRegionName
264
284
  ```
265
285
 
266
- Not allowed:
267
-
268
- ```bash
269
- direct dictionaries get-geo-regions \
270
- --region-ids 225,187 \
271
- --fields GeoRegionId,GeoRegionName
272
- ```
286
+ Not allowed: splitting a canonical `direct ...` command over multiple shell
287
+ lines with `\`.
273
288
 
274
289
  #### Flag Design Rules
275
290
 
@@ -295,12 +310,8 @@ Use:
295
310
  direct changes check-campaigns --timestamp 2026-04-14T00:00:00
296
311
  ```
297
312
 
298
- Do not use:
299
-
300
- ```bash
301
- direct changes check-campaigns --timestamp 2026-04-14T00:00:00Z
302
- direct changes check-campaigns --timestamp "2026-04-14 00:00:00"
303
- ```
313
+ Do not use: a timestamp with a `Z` suffix, or a quoted timestamp that contains
314
+ a space between the date and time.
304
315
 
305
316
  #### Documentation Contract
306
317
 
@@ -322,17 +333,9 @@ direct dynamicads set-bids --id 789 --bid 12500000 --context-bid 9000000 --prior
322
333
  direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-names Москва,Санкт-Петербург --fields GeoRegionId,GeoRegionName
323
334
  ```
324
335
 
325
- Invalid examples:
326
-
327
- ```bash
328
- direct dictionaries get-geo-regions --json '{"GeoRegionIds":[225]}' --fields GeoRegionId,GeoRegionName
329
- direct dynamicads set-bids --id 789 --bid 12500000 --json '{"StrategyPriority":"HIGH"}'
330
- direct dictionaries get-geo-regions \
331
- --region-ids 225 \
332
- --fields GeoRegionId,GeoRegionName
333
- direct changes check-campaigns --timestamp 2026-04-14T00:00:00Z
334
- direct changes check-campaigns --timestamp "2026-04-14 00:00:00"
335
- ```
336
+ Invalid examples include command lines that pass raw JSON flags, use shell
337
+ line continuations, add timezone suffixes to CLI datetimes, or quote
338
+ space-separated datetime values.
336
339
 
337
340
  #### Campaigns
338
341
 
@@ -444,8 +447,8 @@ direct dynamicads set-bids --id 789 --bid 12500000 --context-bid 9000000 --prior
444
447
 
445
448
  # Shared bidding strategies
446
449
  direct strategies get --limit 5
447
- direct strategies add --name "Shared Clicks" --type WbMaximumClicks --params '{"SpendLimit":1000000000,"AverageCpc":30000000}' --dry-run
448
- direct strategies update --id 42 --params '{"AverageCpc":35000000}' --dry-run
450
+ direct strategies add --name "Shared Clicks" --type WbMaximumClicks --spend-limit 1000000000 --average-cpc 30000000 --dry-run
451
+ direct strategies update --id 42 --type WbMaximumClicks --average-cpc 35000000 --dry-run
449
452
  direct strategies archive --id 42 --dry-run
450
453
 
451
454
  # Dynamic feed ad targets
@@ -620,6 +623,11 @@ The report contains one row per `WRITE_SANDBOX` command:
620
623
  The same OAuth token works for both production and the sandbox; no separate
621
624
  sandbox token is needed.
622
625
 
626
+ For `v4account` sandbox smoke, `enable-shared-account` uses
627
+ `YANDEX_DIRECT_V4ACCOUNT_CLIENT_LOGIN` or falls back to `YANDEX_DIRECT_LOGIN`.
628
+ `account-management` requires `YANDEX_DIRECT_V4ACCOUNT_ACCOUNT_ID`; without it
629
+ the runner reports `NOT_COVERED` for that command.
630
+
623
631
  #### Re-recording write cassettes
624
632
 
625
633
  The `integration_write` pytest tier still replays stored write-test traffic
@@ -740,7 +748,9 @@ OAuth и profile-команды:
740
748
  ```bash
741
749
  direct auth login
742
750
  direct auth login --profile agency1
751
+ direct auth login --profile agency1 --format json
743
752
  direct auth login --code abc123 --profile agency1
753
+ printf '%s\n' abc123 | direct auth login --code - --profile agency1
744
754
  direct auth list
745
755
  direct auth use --profile agency1
746
756
  direct auth status --profile agency1
@@ -749,6 +759,10 @@ direct --profile agency1 campaigns get
749
759
 
750
760
  Примечания:
751
761
  - OAuth profiles сохраняют refresh token и автоматически обновляют access token.
762
+ - В non-interactive shell сначала выполните `direct auth login --profile NAME`, затем завершите через `direct auth login --code - --profile NAME` и передайте browser code через stdin.
763
+ - `direct auth login --code CODE --profile NAME` сохраняется для совместимости, но автоматизация должна использовать `--code -`, чтобы не раскрывать код в process arguments.
764
+ - Если первый non-interactive шаг включает `--client-secret`, secret запоминается для последующего completion step.
765
+ - Если profile уже хранит confidential OAuth client, `direct auth login --code CODE --profile NAME` использует сохраненные `client_id` и `client_secret`.
752
766
  - `direct auth login --oauth-token TOKEN` импортирует access token вручную и не включает auto-refresh.
753
767
 
754
768
  Порядок выбора credentials:
@@ -890,13 +904,8 @@ Allowed:
890
904
  direct dictionaries get-geo-regions --region-ids 225,187 --fields GeoRegionId,GeoRegionName
891
905
  ```
892
906
 
893
- Not allowed:
894
-
895
- ```bash
896
- direct dictionaries get-geo-regions \
897
- --region-ids 225,187 \
898
- --fields GeoRegionId,GeoRegionName
899
- ```
907
+ Not allowed: splitting a canonical `direct ...` command over multiple shell
908
+ lines with `\`.
900
909
 
901
910
  #### Flag Design Rules
902
911
 
@@ -922,12 +931,8 @@ Use:
922
931
  direct changes check-campaigns --timestamp 2026-04-14T00:00:00
923
932
  ```
924
933
 
925
- Do not use:
926
-
927
- ```bash
928
- direct changes check-campaigns --timestamp 2026-04-14T00:00:00Z
929
- direct changes check-campaigns --timestamp "2026-04-14 00:00:00"
930
- ```
934
+ Do not use: a timestamp with a `Z` suffix, or a quoted timestamp that contains
935
+ a space between the date and time.
931
936
 
932
937
  #### Documentation Contract
933
938
 
@@ -948,17 +953,9 @@ direct dynamicads set-bids --id 789 --bid 12500000
948
953
  direct dictionaries get-geo-regions --region-ids 225 --fields GeoRegionId,GeoRegionName
949
954
  ```
950
955
 
951
- Invalid examples:
952
-
953
- ```bash
954
- direct dictionaries get-geo-regions --json '{"GeoRegionIds":[225]}' --fields GeoRegionId,GeoRegionName
955
- direct dynamicads set-bids --id 789 --bid 12500000 --json '{"StrategyPriority":"HIGH"}'
956
- direct dictionaries get-geo-regions \
957
- --region-ids 225 \
958
- --fields GeoRegionId,GeoRegionName
959
- direct changes check-campaigns --timestamp 2026-04-14T00:00:00Z
960
- direct changes check-campaigns --timestamp "2026-04-14 00:00:00"
961
- ```
956
+ Invalid examples include command lines that pass raw JSON flags, use shell
957
+ line continuations, add timezone suffixes to CLI datetimes, or quote
958
+ space-separated datetime values.
962
959
 
963
960
  #### Кампании
964
961
 
@@ -1070,8 +1067,8 @@ direct dynamicads set-bids --id 789 --bid 12500000 --context-bid 9000000 --prior
1070
1067
 
1071
1068
  # Общие стратегии ставок
1072
1069
  direct strategies get --limit 5
1073
- direct strategies add --name "Общая стратегия" --type WbMaximumClicks --params '{"SpendLimit":1000000000,"AverageCpc":30000000}' --dry-run
1074
- direct strategies update --id 42 --params '{"AverageCpc":35000000}' --dry-run
1070
+ direct strategies add --name "Общая стратегия" --type WbMaximumClicks --spend-limit 1000000000 --average-cpc 30000000 --dry-run
1071
+ direct strategies update --id 42 --type WbMaximumClicks --average-cpc 35000000 --dry-run
1075
1072
  direct strategies archive --id 42 --dry-run
1076
1073
 
1077
1074
  # Динамические таргеты по фиду
@@ -1215,6 +1212,11 @@ best-effort. Отчёт содержит одну строку на каждую
1215
1212
  Один и тот же OAuth-токен работает и для продакшена, и для sandbox; отдельный
1216
1213
  sandbox-токен не нужен.
1217
1214
 
1215
+ Для `v4account` sandbox smoke команда `enable-shared-account` использует
1216
+ `YANDEX_DIRECT_V4ACCOUNT_CLIENT_LOGIN` или fallback на `YANDEX_DIRECT_LOGIN`.
1217
+ Для `account-management` нужна переменная
1218
+ `YANDEX_DIRECT_V4ACCOUNT_ACCOUNT_ID`; без неё runner покажет `NOT_COVERED`.
1219
+
1218
1220
  #### Перезапись write-кассет
1219
1221
 
1220
1222
  Уровень `integration_write` в pytest всё ещё воспроизводит сохранённый
@@ -43,7 +43,9 @@ OAuth and profile commands:
43
43
  ```bash
44
44
  direct auth login
45
45
  direct auth login --profile agency1
46
+ direct auth login --profile agency1 --format json
46
47
  direct auth login --code abc123 --profile agency1
48
+ printf '%s\n' abc123 | direct auth login --code - --profile agency1
47
49
  direct auth list
48
50
  direct auth use --profile agency1
49
51
  direct auth status --profile agency1
@@ -56,6 +58,10 @@ Notes:
56
58
  - `--login` remains Direct client login.
57
59
  - Authorization is performed via `direct auth login`.
58
60
  - OAuth profiles store refresh tokens and refresh access tokens automatically.
61
+ - 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.
62
+ - `direct auth login --code CODE --profile NAME` remains supported for compatibility, but automation should use `--code -` to avoid exposing the code in process arguments.
63
+ - If the first non-interactive step includes `--client-secret`, the secret is remembered for the matching completion step.
64
+ - If a profile already stores a confidential OAuth client, `direct auth login --code CODE --profile NAME` reuses the saved `client_id` and `client_secret`.
59
65
  - `direct auth login --oauth-token TOKEN` is a manual access-token import and does not auto-refresh.
60
66
  - Alias `auth_login` is not supported.
61
67
 
@@ -116,6 +122,19 @@ direct v4events get-events-log --from 2026-04-14T00:00:00 --to 2026-04-15T00:00:
116
122
  direct v4events get-events-log --from 2026-04-14T00:00:00 --to 2026-04-15T00:00:00 --currency RUB --limit 100 --offset 0 --format table
117
123
  ```
118
124
 
125
+ ### V4 Live Wordstat Reports
126
+
127
+ Wordstat reports are asynchronous. Direct CLI makes exactly one API call per
128
+ command and does not poll automatically; repeat `list-reports` or `get-report`
129
+ yourself until the report is ready.
130
+
131
+ ```bash
132
+ direct v4wordstat create-report --phrases "buy laptop,buy desktop" --geo-ids 213
133
+ direct v4wordstat list-reports --format table
134
+ direct v4wordstat get-report --report-id 123 --format table
135
+ direct v4wordstat delete-report --report-id 123
136
+ ```
137
+
119
138
  ### V4 Live Finance
120
139
 
121
140
  Finance methods require an extra financial token for money operations. In the
@@ -143,14 +162,15 @@ direct v4finance pay-campaigns --campaign-ids 123,456 --amount 100.50 --currency
143
162
 
144
163
  ### V4 Live Shared Account
145
164
 
146
- Shared-account mutations are dry-run-only in this release and always require
147
- `--dry-run`. These commands follow the official v4 Live shared-account method
148
- shapes: `EnableSharedAccount` accepts one client `Login`, and
149
- `AccountManagement` updates shared-account settings through `Accounts`.
165
+ Shared-account mutations require `--dry-run` in production and can be sent live
166
+ only with top-level `--sandbox`. These commands follow the official v4 Live
167
+ shared-account method shapes: `EnableSharedAccount` accepts one client `Login`,
168
+ and `AccountManagement` updates shared-account settings through `Accounts`.
150
169
 
151
170
  ```bash
152
171
  direct v4account enable-shared-account --client-login client-login --dry-run
153
172
  direct v4account account-management --action Update --account-id 1327944 --day-budget 100.50 --spend-mode Default --money-in-sms Yes --money-out-sms No --email ops@example.com --money-warning-value 25 --dry-run
173
+ direct --sandbox v4account enable-shared-account --client-login client-login
154
174
  ```
155
175
 
156
176
  ### CLI Convention
@@ -220,13 +240,8 @@ Allowed:
220
240
  direct dictionaries get-geo-regions --region-ids 225,187 --fields GeoRegionId,GeoRegionName
221
241
  ```
222
242
 
223
- Not allowed:
224
-
225
- ```bash
226
- direct dictionaries get-geo-regions \
227
- --region-ids 225,187 \
228
- --fields GeoRegionId,GeoRegionName
229
- ```
243
+ Not allowed: splitting a canonical `direct ...` command over multiple shell
244
+ lines with `\`.
230
245
 
231
246
  #### Flag Design Rules
232
247
 
@@ -252,12 +267,8 @@ Use:
252
267
  direct changes check-campaigns --timestamp 2026-04-14T00:00:00
253
268
  ```
254
269
 
255
- Do not use:
256
-
257
- ```bash
258
- direct changes check-campaigns --timestamp 2026-04-14T00:00:00Z
259
- direct changes check-campaigns --timestamp "2026-04-14 00:00:00"
260
- ```
270
+ Do not use: a timestamp with a `Z` suffix, or a quoted timestamp that contains
271
+ a space between the date and time.
261
272
 
262
273
  #### Documentation Contract
263
274
 
@@ -279,17 +290,9 @@ direct dynamicads set-bids --id 789 --bid 12500000 --context-bid 9000000 --prior
279
290
  direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-names Москва,Санкт-Петербург --fields GeoRegionId,GeoRegionName
280
291
  ```
281
292
 
282
- Invalid examples:
283
-
284
- ```bash
285
- direct dictionaries get-geo-regions --json '{"GeoRegionIds":[225]}' --fields GeoRegionId,GeoRegionName
286
- direct dynamicads set-bids --id 789 --bid 12500000 --json '{"StrategyPriority":"HIGH"}'
287
- direct dictionaries get-geo-regions \
288
- --region-ids 225 \
289
- --fields GeoRegionId,GeoRegionName
290
- direct changes check-campaigns --timestamp 2026-04-14T00:00:00Z
291
- direct changes check-campaigns --timestamp "2026-04-14 00:00:00"
292
- ```
293
+ Invalid examples include command lines that pass raw JSON flags, use shell
294
+ line continuations, add timezone suffixes to CLI datetimes, or quote
295
+ space-separated datetime values.
293
296
 
294
297
  #### Campaigns
295
298
 
@@ -401,8 +404,8 @@ direct dynamicads set-bids --id 789 --bid 12500000 --context-bid 9000000 --prior
401
404
 
402
405
  # Shared bidding strategies
403
406
  direct strategies get --limit 5
404
- direct strategies add --name "Shared Clicks" --type WbMaximumClicks --params '{"SpendLimit":1000000000,"AverageCpc":30000000}' --dry-run
405
- direct strategies update --id 42 --params '{"AverageCpc":35000000}' --dry-run
407
+ direct strategies add --name "Shared Clicks" --type WbMaximumClicks --spend-limit 1000000000 --average-cpc 30000000 --dry-run
408
+ direct strategies update --id 42 --type WbMaximumClicks --average-cpc 35000000 --dry-run
406
409
  direct strategies archive --id 42 --dry-run
407
410
 
408
411
  # Dynamic feed ad targets
@@ -577,6 +580,11 @@ The report contains one row per `WRITE_SANDBOX` command:
577
580
  The same OAuth token works for both production and the sandbox; no separate
578
581
  sandbox token is needed.
579
582
 
583
+ For `v4account` sandbox smoke, `enable-shared-account` uses
584
+ `YANDEX_DIRECT_V4ACCOUNT_CLIENT_LOGIN` or falls back to `YANDEX_DIRECT_LOGIN`.
585
+ `account-management` requires `YANDEX_DIRECT_V4ACCOUNT_ACCOUNT_ID`; without it
586
+ the runner reports `NOT_COVERED` for that command.
587
+
580
588
  #### Re-recording write cassettes
581
589
 
582
590
  The `integration_write` pytest tier still replays stored write-test traffic
@@ -697,7 +705,9 @@ OAuth и profile-команды:
697
705
  ```bash
698
706
  direct auth login
699
707
  direct auth login --profile agency1
708
+ direct auth login --profile agency1 --format json
700
709
  direct auth login --code abc123 --profile agency1
710
+ printf '%s\n' abc123 | direct auth login --code - --profile agency1
701
711
  direct auth list
702
712
  direct auth use --profile agency1
703
713
  direct auth status --profile agency1
@@ -706,6 +716,10 @@ direct --profile agency1 campaigns get
706
716
 
707
717
  Примечания:
708
718
  - OAuth profiles сохраняют refresh token и автоматически обновляют access token.
719
+ - В non-interactive shell сначала выполните `direct auth login --profile NAME`, затем завершите через `direct auth login --code - --profile NAME` и передайте browser code через stdin.
720
+ - `direct auth login --code CODE --profile NAME` сохраняется для совместимости, но автоматизация должна использовать `--code -`, чтобы не раскрывать код в process arguments.
721
+ - Если первый non-interactive шаг включает `--client-secret`, secret запоминается для последующего completion step.
722
+ - Если profile уже хранит confidential OAuth client, `direct auth login --code CODE --profile NAME` использует сохраненные `client_id` и `client_secret`.
709
723
  - `direct auth login --oauth-token TOKEN` импортирует access token вручную и не включает auto-refresh.
710
724
 
711
725
  Порядок выбора credentials:
@@ -847,13 +861,8 @@ Allowed:
847
861
  direct dictionaries get-geo-regions --region-ids 225,187 --fields GeoRegionId,GeoRegionName
848
862
  ```
849
863
 
850
- Not allowed:
851
-
852
- ```bash
853
- direct dictionaries get-geo-regions \
854
- --region-ids 225,187 \
855
- --fields GeoRegionId,GeoRegionName
856
- ```
864
+ Not allowed: splitting a canonical `direct ...` command over multiple shell
865
+ lines with `\`.
857
866
 
858
867
  #### Flag Design Rules
859
868
 
@@ -879,12 +888,8 @@ Use:
879
888
  direct changes check-campaigns --timestamp 2026-04-14T00:00:00
880
889
  ```
881
890
 
882
- Do not use:
883
-
884
- ```bash
885
- direct changes check-campaigns --timestamp 2026-04-14T00:00:00Z
886
- direct changes check-campaigns --timestamp "2026-04-14 00:00:00"
887
- ```
891
+ Do not use: a timestamp with a `Z` suffix, or a quoted timestamp that contains
892
+ a space between the date and time.
888
893
 
889
894
  #### Documentation Contract
890
895
 
@@ -905,17 +910,9 @@ direct dynamicads set-bids --id 789 --bid 12500000
905
910
  direct dictionaries get-geo-regions --region-ids 225 --fields GeoRegionId,GeoRegionName
906
911
  ```
907
912
 
908
- Invalid examples:
909
-
910
- ```bash
911
- direct dictionaries get-geo-regions --json '{"GeoRegionIds":[225]}' --fields GeoRegionId,GeoRegionName
912
- direct dynamicads set-bids --id 789 --bid 12500000 --json '{"StrategyPriority":"HIGH"}'
913
- direct dictionaries get-geo-regions \
914
- --region-ids 225 \
915
- --fields GeoRegionId,GeoRegionName
916
- direct changes check-campaigns --timestamp 2026-04-14T00:00:00Z
917
- direct changes check-campaigns --timestamp "2026-04-14 00:00:00"
918
- ```
913
+ Invalid examples include command lines that pass raw JSON flags, use shell
914
+ line continuations, add timezone suffixes to CLI datetimes, or quote
915
+ space-separated datetime values.
919
916
 
920
917
  #### Кампании
921
918
 
@@ -1027,8 +1024,8 @@ direct dynamicads set-bids --id 789 --bid 12500000 --context-bid 9000000 --prior
1027
1024
 
1028
1025
  # Общие стратегии ставок
1029
1026
  direct strategies get --limit 5
1030
- direct strategies add --name "Общая стратегия" --type WbMaximumClicks --params '{"SpendLimit":1000000000,"AverageCpc":30000000}' --dry-run
1031
- direct strategies update --id 42 --params '{"AverageCpc":35000000}' --dry-run
1027
+ direct strategies add --name "Общая стратегия" --type WbMaximumClicks --spend-limit 1000000000 --average-cpc 30000000 --dry-run
1028
+ direct strategies update --id 42 --type WbMaximumClicks --average-cpc 35000000 --dry-run
1032
1029
  direct strategies archive --id 42 --dry-run
1033
1030
 
1034
1031
  # Динамические таргеты по фиду
@@ -1172,6 +1169,11 @@ best-effort. Отчёт содержит одну строку на каждую
1172
1169
  Один и тот же OAuth-токен работает и для продакшена, и для sandbox; отдельный
1173
1170
  sandbox-токен не нужен.
1174
1171
 
1172
+ Для `v4account` sandbox smoke команда `enable-shared-account` использует
1173
+ `YANDEX_DIRECT_V4ACCOUNT_CLIENT_LOGIN` или fallback на `YANDEX_DIRECT_LOGIN`.
1174
+ Для `account-management` нужна переменная
1175
+ `YANDEX_DIRECT_V4ACCOUNT_ACCOUNT_ID`; без неё runner покажет `NOT_COVERED`.
1176
+
1175
1177
  #### Перезапись write-кассет
1176
1178
 
1177
1179
  Уровень `integration_write` в pytest всё ещё воспроизводит сохранённый
@@ -31,6 +31,7 @@ YANDEX_OAUTH_TOKEN_URL = "https://oauth.yandex.ru/token"
31
31
  DEFAULT_OAUTH_CLIENT_ID = "dcf15d9625f6471d94d6d054d52017ba"
32
32
  AUTH_STORE_PATH = Path.home() / ".direct-cli" / "auth.json"
33
33
  OAUTH_REFRESH_SKEW_SECONDS = 60
34
+ PENDING_PKCE_TTL_SECONDS = 600
34
35
 
35
36
 
36
37
  def op_read(ref: str) -> str:
@@ -161,10 +162,17 @@ def load_auth_store(path: Optional[Path] = None) -> Dict[str, Any]:
161
162
  profiles = data.get("profiles")
162
163
  if not isinstance(profiles, dict):
163
164
  profiles = {}
165
+ pending_pkce = data.get("pending_pkce")
166
+ if not isinstance(pending_pkce, dict):
167
+ pending_pkce = {}
164
168
  active = data.get("active_profile")
165
169
  if active is not None and not isinstance(active, str):
166
170
  active = None
167
- return {"profiles": profiles, "active_profile": active}
171
+ return {
172
+ "profiles": profiles,
173
+ "active_profile": active,
174
+ "pending_pkce": pending_pkce,
175
+ }
168
176
 
169
177
 
170
178
  def save_auth_store(data: Dict[str, Any], path: Optional[Path] = None) -> None:
@@ -173,6 +181,95 @@ def save_auth_store(data: Dict[str, Any], path: Optional[Path] = None) -> None:
173
181
  _write_json(store_path, data)
174
182
 
175
183
 
184
+ def save_pending_pkce(
185
+ profile: str,
186
+ client_id: str,
187
+ code_verifier: str,
188
+ login: Optional[str] = None,
189
+ created_at: Optional[float] = None,
190
+ path: Optional[Path] = None,
191
+ ) -> Dict[str, Any]:
192
+ """Save pending PKCE state for a profile."""
193
+ now = time.time() if created_at is None else float(created_at)
194
+ item: Dict[str, Any] = {
195
+ "type": "pkce",
196
+ "client_id": client_id,
197
+ "code_verifier": code_verifier,
198
+ "login": login,
199
+ "created_at": now,
200
+ "expires_at": now + PENDING_PKCE_TTL_SECONDS,
201
+ }
202
+ store = load_auth_store(path=path)
203
+ store["pending_pkce"][profile] = item
204
+ save_auth_store(store, path=path)
205
+ return item
206
+
207
+
208
+ def save_pending_confidential_auth(
209
+ profile: str,
210
+ client_id: str,
211
+ client_secret: str,
212
+ login: Optional[str] = None,
213
+ created_at: Optional[float] = None,
214
+ path: Optional[Path] = None,
215
+ ) -> Dict[str, Any]:
216
+ """Save pending confidential-client OAuth state for a profile."""
217
+ now = time.time() if created_at is None else float(created_at)
218
+ item: Dict[str, Any] = {
219
+ "type": "confidential",
220
+ "client_id": client_id,
221
+ "client_secret": client_secret,
222
+ "login": login,
223
+ "created_at": now,
224
+ "expires_at": now + PENDING_PKCE_TTL_SECONDS,
225
+ }
226
+ store = load_auth_store(path=path)
227
+ store["pending_pkce"][profile] = item
228
+ save_auth_store(store, path=path)
229
+ return item
230
+
231
+
232
+ def get_pending_pkce(
233
+ profile: str, path: Optional[Path] = None
234
+ ) -> Optional[Dict[str, Any]]:
235
+ """Return pending OAuth state for a profile when it has the expected shape."""
236
+ store = load_auth_store(path=path)
237
+ item = store["pending_pkce"].get(profile)
238
+ if not isinstance(item, dict):
239
+ return None
240
+ client_id = item.get("client_id")
241
+ expires_at = item.get("expires_at")
242
+ if (
243
+ not isinstance(client_id, str)
244
+ or not client_id
245
+ or not isinstance(expires_at, (int, float))
246
+ ):
247
+ return None
248
+ auth_type = item.get("type")
249
+ code_verifier = item.get("code_verifier")
250
+ client_secret = item.get("client_secret")
251
+ if auth_type == "confidential":
252
+ if not isinstance(client_secret, str) or not client_secret:
253
+ return None
254
+ elif not isinstance(code_verifier, str) or not code_verifier:
255
+ return None
256
+ else:
257
+ auth_type = "pkce"
258
+ result = dict(item)
259
+ result["type"] = auth_type
260
+ login = result.get("login")
261
+ if login is not None and not isinstance(login, str):
262
+ result["login"] = None
263
+ return result
264
+
265
+
266
+ def remove_pending_pkce(profile: str, path: Optional[Path] = None) -> None:
267
+ """Remove pending PKCE state for a profile if present."""
268
+ store = load_auth_store(path=path)
269
+ store["pending_pkce"].pop(profile, None)
270
+ save_auth_store(store, path=path)
271
+
272
+
176
273
  def save_oauth_profile(
177
274
  profile: str,
178
275
  token: str,
@@ -45,12 +45,9 @@ from .commands.balance import balance
45
45
  from .commands.v4events import v4events
46
46
  from .commands.v4finance import v4finance
47
47
  from .commands.v4account import v4account
48
- from .commands.v4shells import (
49
- v4forecast,
50
- v4meta,
51
- v4wordstat,
52
- )
48
+ from .commands.v4shells import v4forecast, v4meta
53
49
  from .commands.v4goals import v4goals
50
+ from .commands.v4wordstat import v4wordstat
54
51
 
55
52
  # Load .env file
56
53
  load_dotenv()
@@ -178,9 +178,12 @@ def set_bids(ctx, target_id, adgroup_id, campaign_id, context_bid, priority, dry
178
178
  if priority:
179
179
  bid_data["StrategyPriority"] = priority
180
180
  bid_fields = {k for k in ("ContextBid", "StrategyPriority") if k in bid_data}
181
- if not bid_data:
181
+ selector_fields = {
182
+ k for k in ("Id", "AdGroupId", "CampaignId") if k in bid_data
183
+ }
184
+ if not selector_fields:
182
185
  raise click.UsageError(
183
- "Provide target selection and bid fields for set-bids"
186
+ "Provide a target selector (--id, --adgroup-id, or --campaign-id)"
184
187
  )
185
188
  if not bid_fields:
186
189
  raise click.UsageError(