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.
- {direct_cli-0.3.4 → direct_cli-0.3.6}/PKG-INFO +59 -57
- {direct_cli-0.3.4 → direct_cli-0.3.6}/README.md +58 -56
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/auth.py +98 -1
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/cli.py +2 -5
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/audiencetargets.py +5 -2
- direct_cli-0.3.6/direct_cli/commands/auth.py +432 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/bidmodifiers.py +3 -20
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/campaigns.py +106 -1
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/dictionaries.py +3 -5
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/dynamicads.py +5 -2
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/dynamicfeedadtargets.py +1 -3
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/strategies.py +154 -34
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/v4account.py +78 -15
- direct_cli-0.3.6/direct_cli/commands/v4wordstat.py +157 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/smoke_matrix.py +6 -2
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/v4_contracts.py +37 -16
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli.egg-info/PKG-INFO +59 -57
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli.egg-info/SOURCES.txt +4 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/pyproject.toml +1 -1
- {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/sandbox_write_live.py +122 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/test_safe_commands.sh +6 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/api_coverage_payloads.py +4 -0
- direct_cli-0.3.6/tests/test_auth_oauth.py +1495 -0
- direct_cli-0.3.6/tests/test_cli_contract.py +192 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_dry_run.py +149 -3
- direct_cli-0.3.6/tests/test_low_coverage_payloads.py +853 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_smoke_matrix.py +153 -3
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4_safety.py +4 -4
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4account.py +109 -3
- direct_cli-0.3.6/tests/test_v4wordstat.py +250 -0
- direct_cli-0.3.4/direct_cli/commands/auth.py +0 -202
- direct_cli-0.3.4/tests/test_auth_oauth.py +0 -703
- {direct_cli-0.3.4 → direct_cli-0.3.6}/.env.example +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/.github/copilot-instructions.md +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/.github/workflows/api-coverage.yml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/.github/workflows/claude-code-review.yml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/.github/workflows/claude.yml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/.github/workflows/quality.yml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/.gitignore +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/AGENTS.md +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/CHANGELOG.md +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/CLAUDE.md +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/MANIFEST.in +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/__init__.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_deprecated.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_smoke_probes.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/__init__.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/__init__.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/endpoints.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/exceptions.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/resource_mapping.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.pyi +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/v4/__init__.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.pyi +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/_vendor/tapi_yandex_direct/v4/resource_mapping.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/api.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/__init__.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/adextensions.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/adgroups.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/adimages.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/ads.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/advideos.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/agencyclients.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/balance.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/bids.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/businesses.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/changes.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/clients.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/creatives.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/feeds.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/keywordbids.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/keywords.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/keywordsresearch.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/leads.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/negativekeywordsharedsets.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/reports.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/retargeting.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/sitelinks.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/smartadtargets.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/turbopages.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/v4events.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/v4finance.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/v4goals.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/v4shells.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/commands/vcards.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/output.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/reports_coverage.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/utils.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/v4/__init__.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/v4/money.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli/wsdl_coverage.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli.egg-info/dependency_links.txt +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli.egg-info/entry_points.txt +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli.egg-info/requires.txt +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/direct_cli.egg-info/top_level.txt +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/docs/superpowers/plans/2026-04-12-issue-32-completion.md +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/docs/superpowers/specs/2026-04-23-vendor-tapi-yandex-direct-design.md +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/anonymize_cassettes.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/build_api_coverage_checklist.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/build_api_coverage_report.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/check_reports_drift.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/check_wsdl_drift.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/patch_vendor_imports.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/refresh_reports_cache.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/refresh_wsdl_cache.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/release_pypi.sh +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/test_dangerous_commands.sh +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/test_sandbox_write.sh +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/scripts/update_vendor.sh +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/setup.cfg +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/setup.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/API_COVERAGE.md +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/API_ISSUE_AUDIT.md +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/MANUAL_COVERAGE.md +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/__init__.py +0 -0
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_bids_set.yaml +0 -0
- {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
- {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
- {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
- {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
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_live_write/test_live_draft_keywordbids_set.yaml +0 -0
- {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
- {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
- {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
- {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
- {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
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yaml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteAdGroups.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteAdImages.test_add_delete.yaml +0 -0
- {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
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteAudienceTargets.test_add_delete.yaml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteBidModifiersAdd.test_add_delete_mobile.yaml +0 -0
- {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
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteBids.test_set_bid.yaml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteCampaignDraftLifecycle.test_draft_create_get_delete.yaml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteCampaigns.test_campaign_lifecycle.yaml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteKeywordBids.test_set_keyword_bid.yaml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteKeywords.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteNegativeKeywordSharedSets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yaml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteSitelinks.test_add_delete.yaml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/cassettes/test_integration_write/TestWriteVCards.test_add_delete.yaml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/conftest.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/fixtures/test-video.mp4 +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/reports_cache/raw/fields-list.html +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/reports_cache/raw/headers.html +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/reports_cache/raw/period.html +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/reports_cache/raw/spec.html +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/reports_cache/raw/type.html +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/reports_cache/spec.json +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_api_coverage.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_auth_bw.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_auth_op.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_balance.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_cli.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_comprehensive.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_integration.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_integration_live_write.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_integration_write.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_reports_drift.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_reports_parsing.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_transport_contract.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4_contracts.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4_foundation.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4_live_contracts.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4events.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4finance_money.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4finance_read.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_v4goals.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/test_vendor_imports.py +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/adextensions.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/adgroups.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/adimages.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/ads.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/advideos.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/agencyclients.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/audiencetargets.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/bidmodifiers.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/bids.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/businesses.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/campaigns.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/changes.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/clients.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/creatives.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/dictionaries.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/dynamicfeedadtargets.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/dynamictextadtargets.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/feeds.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/imports/adextensiontypes.xsd +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/imports/general.xsd +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/imports/generalclients.xsd +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/keywordbids.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/keywords.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/keywordsresearch.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/leads.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/negativekeywordsharedsets.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/retargetinglists.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/sitelinks.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/smartadtargets.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/strategies.xml +0 -0
- {direct_cli-0.3.4 → direct_cli-0.3.6}/tests/wsdl_cache/turbopages.xml +0 -0
- {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.
|
|
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
|
|
190
|
-
`--
|
|
191
|
-
shapes: `EnableSharedAccount` accepts one client `Login`,
|
|
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
|
-
|
|
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 --
|
|
448
|
-
direct strategies update --id 42 --
|
|
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
|
-
|
|
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 --
|
|
1074
|
-
direct strategies update --id 42 --
|
|
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
|
|
147
|
-
`--
|
|
148
|
-
shapes: `EnableSharedAccount` accepts one client `Login`,
|
|
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
|
-
|
|
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 --
|
|
405
|
-
direct strategies update --id 42 --
|
|
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
|
-
|
|
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 --
|
|
1031
|
-
direct strategies update --id 42 --
|
|
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 {
|
|
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
|
-
|
|
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
|
|
186
|
+
"Provide a target selector (--id, --adgroup-id, or --campaign-id)"
|
|
184
187
|
)
|
|
185
188
|
if not bid_fields:
|
|
186
189
|
raise click.UsageError(
|