gflow-cli 0.9.1__tar.gz → 0.11.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gflow_cli-0.11.0/.claude/commands/gflow/branch-review.md +13 -0
- gflow_cli-0.11.0/.claude/commands/gflow/pr-council-review.md +11 -0
- gflow_cli-0.11.0/.claude/commands/gflow/predict.md +19 -0
- gflow_cli-0.11.0/.claude/commands/gflow/release.md +241 -0
- gflow_cli-0.11.0/.claude/commands/gflow/scenario.md +23 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.env.template +28 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.github/PULL_REQUEST_TEMPLATE.md +2 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.github/workflows/ci.yml +7 -2
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.github/workflows/release.yml +2 -1
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.gitignore +2 -0
- gflow_cli-0.11.0/.planning/issue-125-fix.md +207 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/AGENTS.md +21 -2
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/CHANGELOG.md +238 -1
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/CLAUDE.md +14 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/CONTRIBUTING.md +27 -3
- gflow_cli-0.11.0/GEMINI.md +27 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/KNOWN_ISSUES.md +41 -10
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/PKG-INFO +15 -3
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/PLAN.md +3 -2
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/README.md +8 -2
- gflow_cli-0.11.0/conftest.py +48 -0
- gflow_cli-0.11.0/docker-compose.yml +47 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/AGENT_GUIDE.md +15 -1
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/ARCHITECTURE.md +12 -8
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/AUTHENTICATION.md +121 -5
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/CONFIGURATION.md +73 -4
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/DATA_LAYER.md +75 -11
- gflow_cli-0.11.0/docs/DEMOS.md +47 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/DEVELOPMENT.md +7 -0
- gflow_cli-0.11.0/docs/E2E_TESTING.md +272 -0
- gflow_cli-0.11.0/docs/EXTERNAL_STORAGE.md +140 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/GITHUB.md +38 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/INDEX.md +15 -1
- gflow_cli-0.11.0/docs/LIVE_VERIFICATION_v0.10.0.md +95 -0
- gflow_cli-0.11.0/docs/LIVE_VERIFICATION_v0.11.0.md +100 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/PROJECT_STATUS.md +11 -2
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/SECURITY.md +29 -2
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/USAGE.md +112 -5
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/USER_GUIDE.md +70 -1
- gflow_cli-0.11.0/docs/assets/demo-split-pf.gif +0 -0
- gflow_cli-0.11.0/docs/superpowers/specs/2026-05-27-public-event-surface-design.md +397 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/examples/README.md +4 -0
- gflow_cli-0.11.0/examples/workflow_chain.py +314 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/llms.txt +1 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/pyproject.toml +37 -2
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/ci/check_doc_links.py +13 -0
- gflow_cli-0.11.0/scripts/dev/capture_i2v_intercept_submit.py +262 -0
- gflow_cli-0.11.0/scripts/dev/capture_i2v_model_select_repro.py +104 -0
- gflow_cli-0.11.0/scripts/dev/capture_i2v_post_bind_state.py +288 -0
- gflow_cli-0.11.0/scripts/dev/capture_locale_invariants.py +235 -0
- gflow_cli-0.11.0/scripts/dev/skillopt/README.md +106 -0
- gflow_cli-0.11.0/scripts/dev/skillopt/harness.py +365 -0
- gflow_cli-0.11.0/scripts/dev/skillopt/tasks.json +242 -0
- gflow_cli-0.11.0/skills/README.md +66 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/skills/gflow-cli/SKILL.md +32 -1
- gflow_cli-0.11.0/skills/pr-council-review/SKILL.md +351 -0
- gflow_cli-0.11.0/skills/predict/SKILL.md +209 -0
- gflow_cli-0.11.0/skills/scenario/SKILL.md +200 -0
- gflow_cli-0.11.0/sonar-project.properties +54 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/__init__.py +1 -1
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/_cli_helpers.py +32 -6
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/_retry.py +7 -4
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/client.py +92 -65
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/dto.py +13 -7
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/image.py +62 -10
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/recaptcha.py +12 -3
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/routes.py +2 -1
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/__init__.py +2 -1
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/_common.py +17 -9
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/_fingerprint.py +5 -5
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/base.py +5 -4
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/experimental/bearer.py +32 -16
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/experimental/evaluate_fetch.py +26 -12
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/experimental/sapisidhash.py +39 -15
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/ui_automation.py +213 -121
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/ui_automation_video.py +430 -82
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/video.py +178 -59
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/auth/__init__.py +5 -2
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/auth/base.py +4 -2
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/auth/factory.py +9 -3
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/auth/internal_chromium.py +31 -10
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/auth/real_chrome.py +19 -7
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/auth/verification.py +18 -9
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/browser_manager.py +23 -10
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/cli.py +73 -7
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/cli_data.py +141 -33
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/cli_image.py +139 -35
- gflow_cli-0.11.0/src/gflow_cli/cli_models.py +121 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/cli_run.py +34 -16
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/cli_video.py +136 -16
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/config.py +34 -2
- gflow_cli-0.11.0/src/gflow_cli/data/migrations/0002_add_cloud_storage.sql +20 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/data/models.py +7 -3
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/data/queries.py +119 -26
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/data/recorder.py +75 -31
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/data/redaction.py +2 -2
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/data/repository.py +45 -16
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/data/store.py +18 -9
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/errors.py +75 -16
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/image_batch.py +125 -50
- gflow_cli-0.11.0/src/gflow_cli/json_output.py +176 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/manifest.py +2 -1
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/observability.py +13 -5
- gflow_cli-0.11.0/src/gflow_cli/paths.py +212 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/profile_store.py +68 -6
- gflow_cli-0.11.0/src/gflow_cli/storage.py +145 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/test_client.py +16 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/test_client_image.py +61 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/test_image.py +44 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/test_video.py +65 -5
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/transports/test_bearer.py +6 -2
- gflow_cli-0.11.0/tests/api/transports/test_transport_timeout.py +98 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/transports/test_ui_automation.py +442 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/transports/test_ui_automation_video.py +290 -2
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/auth/strategies/test_strategies.py +6 -0
- gflow_cli-0.11.0/tests/cli/test_cli_auth_list.py +143 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/cli/test_cli_data.py +56 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/cli/test_cli_image.py +180 -3
- gflow_cli-0.11.0/tests/cli/test_cli_models.py +92 -0
- gflow_cli-0.11.0/tests/cli/test_cli_video.py +582 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/conftest.py +1 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/data/test_recorder.py +59 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/data/test_store_migrations.py +1 -1
- gflow_cli-0.11.0/tests/e2e/conftest.py +123 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/e2e/test_auth_verification_e2e.py +1 -1
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/e2e/test_data_layer_e2e.py +10 -31
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/e2e/test_image_batch_e2e.py +10 -19
- gflow_cli-0.11.0/tests/e2e/test_image_i2i_ref_cap_e2e.py +117 -0
- gflow_cli-0.11.0/tests/e2e/test_json_output_e2e.py +213 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/e2e/test_locale_selectors_e2e.py +1 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/e2e/test_transports_e2e.py +175 -131
- gflow_cli-0.11.0/tests/e2e/test_video_r2v_ref_cap_e2e.py +161 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/e2e/test_video_t2v_e2e.py +3 -31
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/features/test_image_steps.py +1 -0
- gflow_cli-0.11.0/tests/integration/conftest.py +163 -0
- gflow_cli-0.11.0/tests/integration/constants.py +13 -0
- gflow_cli-0.11.0/tests/integration/test_storage_gcs.py +57 -0
- gflow_cli-0.11.0/tests/integration/test_storage_s3.py +87 -0
- gflow_cli-0.11.0/tests/scripts/test_capture_locale_invariants.py +77 -0
- gflow_cli-0.11.0/tests/smoke/__init__.py +0 -0
- gflow_cli-0.11.0/tests/smoke/test_profile_account_smoke.py +181 -0
- gflow_cli-0.11.0/tests/smoke/test_real_flow.py +118 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/test_cli_data.py +197 -0
- gflow_cli-0.11.0/tests/test_data_queries.py +613 -0
- gflow_cli-0.11.0/tests/test_documentation_gate.py +34 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/test_errors.py +26 -0
- gflow_cli-0.11.0/tests/test_json_output.py +148 -0
- gflow_cli-0.11.0/tests/test_marker_registry.py +173 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/test_observability.py +23 -4
- gflow_cli-0.11.0/tests/test_paths.py +211 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/test_profile_store.py +50 -0
- gflow_cli-0.11.0/uv.lock +2477 -0
- gflow_cli-0.9.1/.claude/commands/gflow/pr-council-review.md +0 -265
- gflow_cli-0.9.1/.claude/commands/gflow/release.md +0 -168
- gflow_cli-0.9.1/conftest.py +0 -25
- gflow_cli-0.9.1/scripts/dev/capture_locale_invariants.py +0 -87
- gflow_cli-0.9.1/skills/README.md +0 -28
- gflow_cli-0.9.1/sonar-project.properties +0 -35
- gflow_cli-0.9.1/src/gflow_cli/paths.py +0 -107
- gflow_cli-0.9.1/tests/cli/test_cli_auth_list.py +0 -80
- gflow_cli-0.9.1/tests/cli/test_cli_video.py +0 -208
- gflow_cli-0.9.1/tests/e2e/conftest.py +0 -67
- gflow_cli-0.9.1/tests/smoke/test_real_flow.py +0 -92
- gflow_cli-0.9.1/tests/test_data_queries.py +0 -177
- gflow_cli-0.9.1/tests/test_paths.py +0 -96
- gflow_cli-0.9.1/uv.lock +0 -1169
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.claude/README.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.claude/commands/gflow/changelog.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.claude/commands/gflow/check.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.claude/commands/gflow/doc-review.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.claude/commands/gflow/known-issues.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.claude/commands/gflow/plan.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.continue-here.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.gitattributes +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.github/CODEOWNERS +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.github/copilot-instructions.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.github/dependabot.yml +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.github/workflows/external-pr-triage.yml +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.gitleaks.toml +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.planning/todos/pending/2026-05-11-add-project-logo-and-docs-site-promotion-plan.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.planning/todos/pending/pr-38-review.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.pre-commit-config.yaml +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/.secrets.baseline +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/CONFIGURATION.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/DISCLAIMER.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/LICENSE +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/RELEASE.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/ROADMAP.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/DEBUGGING.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_data_layer.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_image_batch.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_v0.7.0.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_v0.8.1.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_v0.9.0.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_v0.9.1.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_video_download.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/assets/example-run.gif +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/2026-05-17-issue-15-handover.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-09-image-mvp-orchestration.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-09-image-mvp.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-09-video-mvp-orchestration.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-09-video-mvp.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-10-phase-4-hardening-orchestration.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-10-phase-4-hardening.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/2026-05-14-shell-multi-prompt-orchestration.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_FINAL_ARCH.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_FINAL_SEC_UX.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_CODE.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_GEMINI.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_SECURITY.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/IMPLEMENTATION_REVIEW_PYTHON.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/IMPLEMENTATION_REVIEW_SECURITY.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_CODE.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_FOLLOWUP.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_PLANNER.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_SECURITY.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_SECURITY_FOLLOWUP.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/COUNCIL_FINAL_SEC_UX_VERIFIED.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/COUNCIL_REVIEW_PLAN_SECURITY.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/COUNCIL_REVIEW_SPEC_SECURITY.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/PLAN.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/orchestration.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-17-e2e-test-coverage.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-17-issue-15-auth-verification-fix.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-17-issue-15-i2v-bearer-auth.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-17-issue-15-orchestration.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-18-video-phase0-submit-spike.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-19-video-phase-a-execution-state.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-19-video-phase-a-orchestration.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-19-video-phase-a-t2v.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-20-video-download-t2v-cli.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-21-multi-image-prompt-orchestration.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-21-multi-image-prompt.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-22-pr-38-review.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-22-stay-mounted-batch-session-plan.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-23-locale-agnostic-selectors.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-24-data-layer.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-10-phase-4-hardening-design.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-14-shell-multi-prompt-design.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-15-auth-login-real-chrome-design.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-17-e2e-test-coverage-design.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-17-i2v-uploadimage-401-bearer-auth-design.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-17-issue-15-auth-verification-fix-design.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-17-issue-15-root-cause-findings.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-18-ui-automation-video-generation-design.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-21-multi-image-prompt-design.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-22-pr-38-review-design.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-22-stay-mounted-batch-session-design.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-23-locale-agnostic-selectors.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-23-readme-v0.8.1-refresh-design.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-24-data-layer-design.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/docs/superpowers/verifications/2026-05-11-phase-4-stage-g.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/examples/batch_from_config.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/examples/multi_prompt_t2i.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/examples/sample_config.json +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/examples/sample_prompts.txt +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/examples/single_image_t2i.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/samples/README.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/samples/captured/01_upload_image.json +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/samples/captured/02_batchAsyncGenerateVideoText.json +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/samples/captured/04_archive_workflow.json +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/samples/captured/05_createProject.json +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/samples/captured/06_batchGenerateImages.json +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/samples/captured/07_batchGenerateImages_seeded.json +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/samples/captured/08_batchAsyncGenerateVideoStartAndEndImage.json +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/samples/captured/09_batchAsyncGenerateVideoReferenceImages.json +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/samples/captured/10_batchCheckAsyncVideoGenerationStatus_successful.json +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/samples/captured/11_batchCheckAsyncVideoGenerationStatus_failed.json +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/ci/check_repo_hygiene.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/debug_editor.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/debug_gen_settings.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/debug_settings.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/dev/active_plan.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/dev/capture_i2v_frame_slots_dom.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/dev/capture_image_add_media_dom.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/dev/cdp_drive_and_probe.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/dev/monitor_pr_38.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/diag_capture_flow_traffic.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/diag_recaptcha_mint.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/record_demo.ps1 +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/smoke_image.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/smoke_real_chrome_image.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/smoke_video_editor.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/smoke_worker_style.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/scripts/verify_chrome_auth_viability.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/__main__.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/__init__.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/experimental/__init__.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/auth/strategies.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/data/__init__.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/data/migrations/0001_initial.sql +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/data/migrations/__init__.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/src/gflow_cli/exceptions.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tasks/lessons.md +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/test_assets/sample_batch.json +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/test_assets/sample_batch.tsv +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/test_assets/sample_batch_invalid.tsv +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/__init__.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/__init__.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/test_concurrency.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/test_dto.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/test_image_dto.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/test_recaptcha.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/test_retry.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/test_routes.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/transports/__init__.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/transports/test_base.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/transports/test_common.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/transports/test_evaluate_fetch.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/transports/test_factory.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/transports/test_fingerprint.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/transports/test_sapisidhash.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/transports/test_ui_automation_batch.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/api/transports/test_ui_automation_image_mode.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/auth/strategies/test_factory.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/auth/test_verification.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/cli/__init__.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/cli/test_cli_image_seed_removed.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/cli/test_cli_run.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/cli/test_error_handling.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/cli/test_helpers.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/cli/test_t2i_multi_prompt.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/data/__init__.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/data/test_packaging.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/data/test_redaction.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/data/test_repository.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/data/test_settings_and_errors.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/e2e/__init__.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/features/__init__.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/features/auth.feature +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/features/auth_login.feature +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/features/conftest.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/features/image.feature +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/features/test_auth_login_steps.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/features/test_auth_steps.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/features/test_step_collision_guard.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/fixtures/__init__.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/fixtures/seeded_catalog.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/image_batch/__init__.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/image_batch/test_image_manifest.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/image_batch/test_observability_events.py +0 -0
- {gflow_cli-0.9.1/tests/smoke → gflow_cli-0.11.0/tests/integration}/__init__.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/test_auth.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/test_browser_manager.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/test_config.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/test_conftest_isolation.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/test_manifest.py +0 -0
- {gflow_cli-0.9.1 → gflow_cli-0.11.0}/tests/test_smoke.py +0 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Multi-dimensional LLM council review on the current local feature branch — pre-PR review. Same dimensions as `/gflow:pr-council-review` but reads `git diff <base>..HEAD` instead of a PR; never posts to GitHub. Wrapper around skills/pr-council-review/SKILL.md § 8 (branch mode).
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# `/gflow:branch-review [--base <ref>]`
|
|
6
|
+
|
|
7
|
+
**Read `skills/pr-council-review/SKILL.md` and follow its protocol now in BRANCH MODE (§ 8)**, passing `$ARGUMENTS` (optional `--base <ref>`; default `develop`).
|
|
8
|
+
|
|
9
|
+
> Do **not** call `Skill(skill="pr-council-review")` — the repo's `skills/*/SKILL.md` files are plain Markdown, not registered as Skill-tool-invocable (only `.claude/commands/gflow/*` are). Invoking it errors with `Unknown skill: pr-council-review`. Read the file directly instead.
|
|
10
|
+
|
|
11
|
+
The canonical body is `skills/pr-council-review/SKILL.md`. § 8 documents branch-mode-specific behavior: pre-flight, the PR→branch translation table, `release/*` downgrade, SHA drift, and local-only output. All other phases (gather context, detect dimensions, dispatch, synthesize, report) are identical to PR mode.
|
|
12
|
+
|
|
13
|
+
Sibling: `/gflow:pr-council-review <N>` runs the same council against an open PR.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Multi-dimensional LLM council review of an open PR. Five baseline dimensions (correctness, quality, security, tests, memory-hygiene) plus adaptive per-surface dimensions. Sub-agents invoke specialized skills (security-review, code-review, verify). With no argument, lists open PRs ranked by priority. Wrapper around skills/pr-council-review/SKILL.md (canonical body).
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# `/gflow:pr-council-review [PR#]`
|
|
6
|
+
|
|
7
|
+
**Read `skills/pr-council-review/SKILL.md` and follow its protocol now**, treating `$ARGUMENTS` as the PR number (or empty for prioritize-mode). That file is the canonical body: preflight, dimension detection, parallel dispatch, synthesis, report.
|
|
8
|
+
|
|
9
|
+
> Do **not** call `Skill(skill="pr-council-review")` — the repo's `skills/*/SKILL.md` files are plain Markdown, not registered as Skill-tool-invocable (only `.claude/commands/gflow/*` are). Invoking it errors with `Unknown skill: pr-council-review`. Read the file directly instead.
|
|
10
|
+
|
|
11
|
+
Sibling: `/review` is the single-agent Claude-Code built-in (fast, one-pass). Use it for spot-checks; use this command for pre-merge multi-dim audits.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: >
|
|
3
|
+
Pre-implementation 5-persona adversarial analysis for high-stakes gflow-cli proposals.
|
|
4
|
+
Produces a GO / CAUTION / STOP verdict before any code is written.
|
|
5
|
+
Invoke before new transports, auth changes, selector redesigns, schema migrations,
|
|
6
|
+
or any PLAN.md backlog item gated on an investigation step.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# `/gflow:predict [proposal]`
|
|
10
|
+
|
|
11
|
+
**Read `skills/predict/SKILL.md` and follow its protocol now**, passing `$ARGUMENTS` as the proposal description.
|
|
12
|
+
|
|
13
|
+
> Do **not** call `Skill(skill="predict")` — the repo's `skills/*/SKILL.md` files are plain Markdown, not registered as Skill-tool-invocable (only `.claude/commands/gflow/*` are). Invoking it errors with `Unknown skill: predict`. Read the file directly instead.
|
|
14
|
+
|
|
15
|
+
The skill at `skills/predict/SKILL.md` runs five independent expert personas
|
|
16
|
+
(Architect · Security/reCAPTCHA · Performance/Playwright · CLI UX · Devil's Advocate),
|
|
17
|
+
resolves conflicts, and returns a GO / CAUTION / STOP verdict with a confidence score.
|
|
18
|
+
|
|
19
|
+
**Pair with `/gflow:scenario`** after a GO or CAUTION to enumerate edge cases before EXECUTE.
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Cut a new gflow-cli release — bump version, update CHANGELOG, tag, push, and back-merge.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# `/gflow:release` — Cut a new release
|
|
6
|
+
|
|
7
|
+
Follow this sequence verbatim. Every step matters.
|
|
8
|
+
|
|
9
|
+
> **Branch-protection note:** `main` blocks direct pushes. The release commit travels
|
|
10
|
+
> via a `chore/release-vX.Y.Z` branch PR. The signed tag is pushed independently
|
|
11
|
+
> (tag pushes bypass branch protection and trigger the CI release workflow immediately).
|
|
12
|
+
>
|
|
13
|
+
> **Source-branch note (read first):** `develop` is the integration branch — it carries
|
|
14
|
+
> ALL unreleased work and `main` usually lags it. The release branch is cut from
|
|
15
|
+
> **`develop`**, NOT `main`. The PR `chore/release-vX.Y.Z → main` then brings the full
|
|
16
|
+
> integration history onto `main`. Do not expect the work to already be on `main`.
|
|
17
|
+
|
|
18
|
+
## Inputs
|
|
19
|
+
|
|
20
|
+
Ask the user (if not already provided):
|
|
21
|
+
|
|
22
|
+
1. **Version** — the new version (e.g. `0.4.0`, `0.4.0a3`, `1.0.0rc1`). Use PEP 440 prerelease suffixes (`aN`, `bN`, `rcN`). If they don't know, run `/gflow:changelog` first and propose the next bump (PATCH for fixes only, MINOR for new features, MAJOR for breaks).
|
|
23
|
+
2. **Pre-release?** — prerelease versions stay marked as GitHub prereleases. Only the user can say when a release line is ready for the stable tag.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Sequence
|
|
28
|
+
|
|
29
|
+
**1. Review what's queued.**
|
|
30
|
+
|
|
31
|
+
Run `/gflow:changelog` — confirm the `[Unreleased]` block is non-empty and accurate before proceeding.
|
|
32
|
+
|
|
33
|
+
**2. Verify (or triage) a clean working tree.**
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
git status --short
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
If empty, continue. If not, **triage before aborting** — do not blindly stop:
|
|
40
|
+
|
|
41
|
+
- **Auto-injected boilerplate** (e.g. a context-mode routing block appended to
|
|
42
|
+
`CLAUDE.md` by an MCP plugin's SessionStart hook): this is plugin-injected, not
|
|
43
|
+
project content — `git restore` it. Confirm with the user if unsure.
|
|
44
|
+
- **Build/temp artifacts** (e.g. a stray `tmp*.tar.gz` sdist at repo root): delete them.
|
|
45
|
+
- **Genuine uncommitted work:** STOP and tell the user to commit or stash on the
|
|
46
|
+
appropriate branch (never commit straight to `develop`).
|
|
47
|
+
|
|
48
|
+
The tree must be clean before you create the release branch.
|
|
49
|
+
|
|
50
|
+
**3. Verify `develop` is the release source and up-to-date.**
|
|
51
|
+
|
|
52
|
+
The release is cut from `develop`, NOT `main` (see Source-branch note above).
|
|
53
|
+
Confirm direction explicitly — a backwards divergence means a prior back-merge was skipped.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
git fetch origin
|
|
57
|
+
git rev-parse --abbrev-ref HEAD # expect "develop"
|
|
58
|
+
git rev-list --count HEAD..origin/develop # local behind origin — expect 0
|
|
59
|
+
git rev-list --count origin/main..origin/develop # develop AHEAD of main — expect > 0 (the work to release)
|
|
60
|
+
git rev-list --count origin/develop..origin/main # main AHEAD of develop — expect 0
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
If not on `develop`: `git checkout develop && git pull origin develop`.
|
|
64
|
+
If local is behind origin: `git pull origin develop`.
|
|
65
|
+
**If `main` is AHEAD of `develop` (last count > 0): STOP.** A prior release skipped its
|
|
66
|
+
`main → develop` back-merge — recover first (see the `release-back-merge-gap-recovery`
|
|
67
|
+
memory) or the release branch will hit conflicts on `pyproject.toml` / `__init__.py` / `CHANGELOG.md`.
|
|
68
|
+
|
|
69
|
+
**4. Run quality gates.**
|
|
70
|
+
|
|
71
|
+
Run `/gflow:check` — all gates must pass. Abort if any fail.
|
|
72
|
+
|
|
73
|
+
**5. Create a release branch off `develop`.**
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
git checkout develop # ensure the base is develop, not main
|
|
77
|
+
git checkout -b chore/release-v<NEW_VERSION>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
This branch now contains all of `develop` (⊇ `main`) plus your release prep. All
|
|
81
|
+
release prep commits live here; the PR into `main` (step 14) carries the full
|
|
82
|
+
integration history forward.
|
|
83
|
+
|
|
84
|
+
**6. Bump version** in `pyproject.toml`:
|
|
85
|
+
|
|
86
|
+
```toml
|
|
87
|
+
[project]
|
|
88
|
+
version = "<NEW_VERSION>"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**7. Bump package version** in `src/gflow_cli/__init__.py`:
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
__version__ = "<NEW_VERSION>"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**8. Update version assertion tests** if present:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
rg -n "__version__|<OLD_VERSION>|version assertion" tests src pyproject.toml
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**9. Migrate CHANGELOG.**
|
|
104
|
+
|
|
105
|
+
- Move all entries under `## [Unreleased]` to a new `## [<NEW_VERSION>] — YYYY-MM-DD` section.
|
|
106
|
+
- Leave `## [Unreleased]` empty.
|
|
107
|
+
- Update the link footer. Match the repo's existing convention — every prior entry
|
|
108
|
+
uses the `compare/vPREV...vNEW` form, so use that for the new version too (NOT the
|
|
109
|
+
`releases/tag/` form), or `/gflow:doc-review` will flag the inconsistency:
|
|
110
|
+
```
|
|
111
|
+
[Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v<NEW_VERSION>...HEAD
|
|
112
|
+
[<NEW_VERSION>]: https://github.com/ffroliva/gflow-cli/compare/v<PREV_VERSION>...v<NEW_VERSION>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**10. Run the documentation review gate.**
|
|
116
|
+
|
|
117
|
+
Run `/gflow:doc-review` — audit all version refs, INDEX completeness, evidence files, skill files, CHANGELOG footer, and memory files. Fix every **FAIL** before continuing. Fold all discovered fixes into the release prep commit.
|
|
118
|
+
|
|
119
|
+
**11. Commit the release prep.**
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
git add pyproject.toml src/gflow_cli/__init__.py uv.lock CHANGELOG.md
|
|
123
|
+
git add docs/ .claude/commands/gflow/ # include any doc-review fixes
|
|
124
|
+
# doc-review version-currency fixes often also touch ROOT docs — stage them too:
|
|
125
|
+
git add README.md PLAN.md KNOWN_ISSUES.md AGENTS.md llms.txt 2>/dev/null || true
|
|
126
|
+
git status --short # review EVERYTHING staged before committing
|
|
127
|
+
git commit -m "chore(release): v<NEW_VERSION>"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
- **`uv.lock` changes** on every version bump (the editable package version is
|
|
131
|
+
pinned in the lockfile) — it is easy to forget and must ship in this commit.
|
|
132
|
+
- The release-prep commit must NOT carry a `Co-Authored-By` trailer (see reminders).
|
|
133
|
+
|
|
134
|
+
**12. Tag the release commit.** Use `-s` for a signed annotated tag so GitHub shows **"Verified"** AND `.github/workflows/release.yml` passes the signed-tag gate (unsigned or lightweight tags are rejected by CI).
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
git tag -s v<NEW_VERSION> -m "v<NEW_VERSION>"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Signing requirements:
|
|
141
|
+
- **SSH signing (preferred):** `git config --global gpg.format ssh` + `user.signingkey` pointing at your public key.
|
|
142
|
+
- **GPG:** any registered GPG key works.
|
|
143
|
+
- Run `git config --global user.signingkey` to confirm a key is configured.
|
|
144
|
+
|
|
145
|
+
Confirm the tag actually carries a signature (this is what CI checks):
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
git cat-file -p v<NEW_VERSION> | grep -c "BEGIN SSH SIGNATURE" # expect 1 (or "BEGIN PGP SIGNATURE" for GPG)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
> **Benign local-verify error:** `git tag -v v<NEW_VERSION>` may fail with
|
|
152
|
+
> `gpg.ssh.allowedSignersFile needs to be configured`. This is a *local
|
|
153
|
+
> verification-config* gap only — the tag IS validly signed and CI still passes
|
|
154
|
+
> (CI greps for the signature header, above). To make local verify work once and
|
|
155
|
+
> for all, create an allowed-signers file (`<your-email> ssh-rsa AAAA...`) and run
|
|
156
|
+
> `git config --global gpg.ssh.allowedSignersFile <path>`. See the `release-signing`
|
|
157
|
+
> memory for the exact recipe. Do NOT treat this error as a signing failure.
|
|
158
|
+
|
|
159
|
+
**13. Push the tag first** (bypasses branch protection; triggers the CI release workflow immediately):
|
|
160
|
+
|
|
161
|
+
> **⚠ POINT OF NO RETURN — confirm with the user before this push.** Pushing the
|
|
162
|
+
> tag immediately triggers `.github/workflows/release.yml` → **PyPI publish +
|
|
163
|
+
> public GitHub Release**. A pushed release tag must NOT be force-replaced (ship a
|
|
164
|
+
> PATCH instead). Get an explicit go-ahead, then push.
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
git push origin v<NEW_VERSION>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
CI will start building the release. Watch <https://github.com/ffroliva/gflow-cli/actions>.
|
|
171
|
+
Wait for the `Release` run to report **completed / success** and confirm the GitHub
|
|
172
|
+
Release published before continuing (`gh release view v<NEW_VERSION>`).
|
|
173
|
+
|
|
174
|
+
**14. Push the release branch and open the PR.**
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
git push -u origin chore/release-v<NEW_VERSION>
|
|
178
|
+
gh pr create --base main --head chore/release-v<NEW_VERSION> \
|
|
179
|
+
--title "chore(release): v<NEW_VERSION>"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Wait for PR CI to go green (`gh pr checks <N> --watch`), then merge with a **merge
|
|
183
|
+
commit** — never squash:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
gh pr merge <N> --merge --delete-branch
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
> **NEVER `--squash` this PR.** Because the branch was cut from `develop`, the PR
|
|
190
|
+
> carries the entire batch of unreleased integration commits. A squash collapses
|
|
191
|
+
> them into one opaque commit on `main` and destroys that history. `--merge`
|
|
192
|
+
> preserves it. (The release workflow already ran from the tag push in step 13 —
|
|
193
|
+
> this PR is to bring the bump commit + integration history onto `main`.)
|
|
194
|
+
|
|
195
|
+
**15. Back-merge `main` into `develop`.**
|
|
196
|
+
|
|
197
|
+
After the release PR is merged, bring the bump commit back to `develop` so branches stay aligned:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
git checkout develop
|
|
201
|
+
git pull origin develop
|
|
202
|
+
git fetch origin main
|
|
203
|
+
git merge origin/main --no-ff -m "chore: back-merge main (v<NEW_VERSION>) into develop"
|
|
204
|
+
git push origin develop
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
If there are conflicts (rare — only if `develop` has commits that touched the same lines as the bump), resolve them, keeping `develop`'s unreleased work and `main`'s version bump.
|
|
208
|
+
|
|
209
|
+
**16. Report.**
|
|
210
|
+
|
|
211
|
+
Tell the user:
|
|
212
|
+
- Tag push triggered `.github/workflows/release.yml`.
|
|
213
|
+
- Watch <https://github.com/ffroliva/gflow-cli/actions> for the release workflow.
|
|
214
|
+
- On success: PyPI publish + GitHub Release with auto-generated notes.
|
|
215
|
+
- On failure (most common: PyPI Trusted Publishing not yet configured): point to <https://pypi.org/manage/account/publishing/>.
|
|
216
|
+
- `develop` is now synced with `main` (back-merge done in step 15).
|
|
217
|
+
- Next development cycle starts on `develop` — open `## [Unreleased]` in CHANGELOG is ready.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Critical reminders
|
|
222
|
+
|
|
223
|
+
- **ALWAYS** cut the release branch from `develop`, not `main` — `develop` carries the work.
|
|
224
|
+
- **NEVER** `--squash` the release PR into `main` — it destroys the integration history the branch carries. Use `--merge`.
|
|
225
|
+
- **NEVER** skip the `main → develop` back-merge (step 15) — skipping it guarantees conflicts at the next release.
|
|
226
|
+
- **NEVER** add `Co-Authored-By: Claude` (or any AI co-author) to the release commit.
|
|
227
|
+
- **NEVER** force-push a release tag once it's on GitHub. Ship a PATCH fix instead.
|
|
228
|
+
- **NEVER** `--no-verify` past hooks. Fix the underlying issue.
|
|
229
|
+
- **NEVER** push directly to `main` — branch protection will reject it. Always use a PR.
|
|
230
|
+
- A `git tag -v` `allowedSignersFile` error is **benign** (verify-only) — the tag is still signed and CI passes. Don't treat it as a failure.
|
|
231
|
+
- **CONFIRM with the user before the step 13 tag push** — it's the irreversible PyPI + public Release trigger.
|
|
232
|
+
- If quality gates fail at step 4, **STOP**. Surface the failures to the user.
|
|
233
|
+
- If doc-review fails at step 10, **STOP**. Fix before committing.
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## See also
|
|
238
|
+
|
|
239
|
+
- [RELEASE.md](../../../RELEASE.md) — full release protocol, prerelease policy, and checklist
|
|
240
|
+
- [README § Releases](../../../README.md#releases) — release policy and cadence
|
|
241
|
+
- [PLAN § Phase 5](../../../PLAN.md#phase-5--public-alpha-release-on-pypi) — first-release exit criteria
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: >
|
|
3
|
+
Pre-implementation edge-case explorer for gflow-cli features.
|
|
4
|
+
Decomposes a proposed change across 12 gflow-cli-specific dimensions
|
|
5
|
+
(WAF/reCAPTCHA, selector drift, auth lifecycle, batch resume, data layer,
|
|
6
|
+
cross-platform paths, error propagation, observability) and produces a
|
|
7
|
+
severity-ranked scenario table and BDD skeleton.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# `/gflow:scenario [feature description]`
|
|
11
|
+
|
|
12
|
+
**Read `skills/scenario/SKILL.md` and follow its protocol now**, passing `$ARGUMENTS` as the feature or change description.
|
|
13
|
+
|
|
14
|
+
> Do **not** call `Skill(skill="scenario")` — the repo's `skills/*/SKILL.md` files are plain Markdown, not registered as Skill-tool-invocable (only `.claude/commands/gflow/*` are). Invoking it errors with `Unknown skill: scenario`. Read the file directly instead.
|
|
15
|
+
|
|
16
|
+
The skill at `skills/scenario/SKILL.md` covers 12 dimensions tuned to gflow-cli's
|
|
17
|
+
known failure surfaces and outputs:
|
|
18
|
+
- A severity-ranked scenario table (Critical / High / Medium / Low)
|
|
19
|
+
- Must-cover acceptance criteria for the PLAN.md task
|
|
20
|
+
- Suggested BDD `Scenario:` blocks for `tests/features/`
|
|
21
|
+
- Cross-references to open KNOWN_ISSUES entries
|
|
22
|
+
|
|
23
|
+
**Typical order:** `/gflow:predict` → `/gflow:scenario` → PLAN.md task → `/gflow:check` → PR.
|
|
@@ -52,6 +52,34 @@
|
|
|
52
52
|
# Get one at https://aistudio.google.com/apikey
|
|
53
53
|
# GFLOW_CLI_GEMINI_API_KEY=
|
|
54
54
|
|
|
55
|
+
# -----------------------------------------------------------------------------
|
|
56
|
+
# Cloud storage
|
|
57
|
+
# -----------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
# Upload generated assets directly to a cloud bucket instead of saving local
|
|
60
|
+
# asset copies. Supported schemes:
|
|
61
|
+
# gs:// – Google Cloud Storage (requires: pip install 'gflow-cli[gcs]')
|
|
62
|
+
# s3:// – Amazon S3 or any S3-compatible store, e.g. MinIO
|
|
63
|
+
# (requires: pip install 'gflow-cli[s3]')
|
|
64
|
+
#
|
|
65
|
+
# Examples:
|
|
66
|
+
# GFLOW_CLI_STORAGE_URI=gs://my-gcs-bucket/gflow/
|
|
67
|
+
# GFLOW_CLI_STORAGE_URI=s3://my-s3-bucket/gflow/
|
|
68
|
+
# GFLOW_CLI_STORAGE_URI=s3://gflow-test/gflow/ # MinIO local dev
|
|
69
|
+
#
|
|
70
|
+
# For S3 / MinIO you also need the standard AWS SDK env vars:
|
|
71
|
+
# AWS_ACCESS_KEY_ID=minioadmin
|
|
72
|
+
# AWS_SECRET_ACCESS_KEY=minioadmin
|
|
73
|
+
# AWS_ENDPOINT_URL=http://localhost:9000 # omit for real AWS
|
|
74
|
+
# AWS_DEFAULT_REGION=us-east-1
|
|
75
|
+
#
|
|
76
|
+
# For GCS (local emulator):
|
|
77
|
+
# STORAGE_EMULATOR_HOST=http://localhost:4443
|
|
78
|
+
#
|
|
79
|
+
# When unset, assets are saved to GFLOW_CLI_OUTPUT_DIR (local disk). gflow-cli
|
|
80
|
+
# does not dual-write local + cloud copies; configure one storage target per run.
|
|
81
|
+
# GFLOW_CLI_STORAGE_URI=
|
|
82
|
+
|
|
55
83
|
# -----------------------------------------------------------------------------
|
|
56
84
|
# Runtime tuning
|
|
57
85
|
# -----------------------------------------------------------------------------
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
<!-- List the focused commands you ran, plus any checks you could not run. -->
|
|
8
8
|
|
|
9
9
|
- [ ] Focused tests added or updated for behavior changes
|
|
10
|
+
- [ ] Documentation updated or explicitly marked not applicable
|
|
11
|
+
- [ ] `uv run python scripts/ci/check_doc_links.py`
|
|
10
12
|
- [ ] `uv run ruff check src tests`
|
|
11
13
|
- [ ] `uv run pyright src`
|
|
12
14
|
- [ ] Relevant pytest command:
|
|
@@ -6,7 +6,9 @@ on:
|
|
|
6
6
|
pull_request:
|
|
7
7
|
|
|
8
8
|
env:
|
|
9
|
-
|
|
9
|
+
# Suppress Node.js deprecation warnings and align with user request to use Node 22/remove noise.
|
|
10
|
+
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
|
|
11
|
+
NODE_VERSION: '22'
|
|
10
12
|
|
|
11
13
|
jobs:
|
|
12
14
|
# ── Security gate: runs first, on every push/PR, never skippable ──────────
|
|
@@ -44,6 +46,9 @@ jobs:
|
|
|
44
46
|
- name: Repo hygiene (no artefacts, no hardcoded paths)
|
|
45
47
|
run: uv run python scripts/ci/check_repo_hygiene.py
|
|
46
48
|
|
|
49
|
+
- name: Documentation links
|
|
50
|
+
run: uv run python scripts/ci/check_doc_links.py
|
|
51
|
+
|
|
47
52
|
- name: Lint
|
|
48
53
|
run: uv run ruff check src tests
|
|
49
54
|
|
|
@@ -94,7 +99,7 @@ jobs:
|
|
|
94
99
|
continue-on-error: true # graceful if coverage upload was skipped
|
|
95
100
|
|
|
96
101
|
- name: SonarCloud scan
|
|
97
|
-
uses: SonarSource/sonarcloud-github-action@
|
|
102
|
+
uses: SonarSource/sonarcloud-github-action@v5.0.0
|
|
98
103
|
env:
|
|
99
104
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # PR decoration
|
|
100
105
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # set in repo → Settings → Secrets
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Issue #125 fix plan — `gflow video i2v` silently routes to T2V with `omni-flash`
|
|
2
|
+
|
|
3
|
+
**Branch:** `bugfix/issue-125-i2v-t2v` (worktree at `.claude/worktrees/bugfix+issue-125-i2v-t2v/`)
|
|
4
|
+
**Issue:** https://github.com/ffroliva/gflow-cli/issues/125
|
|
5
|
+
**Status:** Plan — awaiting 5-persona council review before implementation.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Root cause (confirmed at zero credit)
|
|
10
|
+
|
|
11
|
+
`omni-flash` does NOT support i2v interpolation (start+end frames). Flow's frontend silently drops the bound mediaIds at submit time and routes the request to `batchAsyncGenerateVideoText` with `image_inputs: null`. The user is charged 1 credit for a pure text-to-video generation that ignores the start/end frames entirely.
|
|
12
|
+
|
|
13
|
+
This is **NOT** the originally hypothesised selector / UI-path bug. The "Add to Prompt" click in `_upload_via_open_dialog` IS correct on both EN and pt-BR locales (probe v1). The frame slots transition correctly (`FRAME_SLOTS_STRUCT.count()` drops 2 → 1 → 0, probe v3). The submit-button selector finds the right "Criar" button (probe v3). The bug is at Flow's model-vs-request-shape compatibility check, which is invisible from the DOM.
|
|
14
|
+
|
|
15
|
+
## 2. Evidence
|
|
16
|
+
|
|
17
|
+
### Zero-credit evidence
|
|
18
|
+
|
|
19
|
+
| Probe | Sequence | Model | Captured URL | startImage | endImage |
|
|
20
|
+
|---|---|---|---|---|---|
|
|
21
|
+
| v4 prod-order | attaches → prompt → submit | (inherits Flow's last = omni-flash) | `batchAsyncGenerateVideoText` ❌ | `null` | `null` |
|
|
22
|
+
| v4 reorder | prompt → attaches → submit | omni-flash | `batchAsyncGenerateVideoText` ❌ | `null` | `null` |
|
|
23
|
+
| **v5 omni-flash + start+end** | attaches → prompt → submit | omni-flash (explicit) | `batchAsyncGenerateVideoText` ❌ | `null` | `null` |
|
|
24
|
+
| **v5 omni-flash + start-only** | Start only → prompt → submit | omni-flash (explicit) | `batchAsyncGenerateVideoText` ❌ | `null` | `null` |
|
|
25
|
+
| **v5 veo-lite + start+end** | attaches → prompt → submit | **veo-lite** | **`batchAsyncGenerateVideoStartAndEndImage` ✓** | **`4e551690...` ✓** | **`700c5522...` ✓** |
|
|
26
|
+
|
|
27
|
+
**Conclusion: omni-flash does NOT support i2v in ANY form** — neither start-only nor start+end. The strict rejection in §3 is verified, not just conservative.
|
|
28
|
+
|
|
29
|
+
Output dirs:
|
|
30
|
+
- `C:\Users\ffrol\gflow-output\i2v-intercept-prodorder-20260530-160535\evidence.json` (omni-flash, broken)
|
|
31
|
+
- `C:\Users\ffrol\gflow-output\i2v-intercept-veolite-20260530-165432\evidence.json` (veo-lite, correct)
|
|
32
|
+
|
|
33
|
+
### Human-session HAR evidence
|
|
34
|
+
|
|
35
|
+
`C:\Users\ffrol\Downloads\labs.google14.har` — manual i2v session on the same account, same UI flow as gflow. The captured generate body shows:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"videoModelKey": "veo_3_1_interpolation_lite", // ← Flow auto-promotes veo_3_1_lite → veo_3_1_interpolation_lite when start+end frames are present
|
|
40
|
+
"startImage": { "mediaId": "3c65f7ed-..." },
|
|
41
|
+
"endImage": { "mediaId": "7e70fd03-..." }
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Paid run evidence
|
|
46
|
+
|
|
47
|
+
The original gflow paid retry (`C:\Users\ffrol\gflow-output\i2v-prompt-retry-20260530-133705\_err2.log`) used `--model omni-flash` (gflow's default), produced an 8s "wake-up in bedroom" stickman video that has zero visual continuity with `01-t2i.jpg` (stickman at desk) or `02-i2i.jpg` (arms-raised triumph at sunrise). Per the structured-log `generate_captured` event, the request URL was `batchAsyncGenerateVideoText` with all-null image_inputs — pure T2V from the prompt alone.
|
|
48
|
+
|
|
49
|
+
**Retroactive impact:** every i2v paid run on `gflow v0.10.0` with the default model (or `--model omni-flash`) has been a silent T2V. The wf-004 promo "drift" was not Veo style-shift — it was a pure T2V.
|
|
50
|
+
|
|
51
|
+
## 3. Scope
|
|
52
|
+
|
|
53
|
+
### In scope (this PR) — council-revised
|
|
54
|
+
|
|
55
|
+
- Add model-vs-mode compatibility helper `VideoModel.supports_i2v_interpolation()` returning False for `OMNI_FLASH`, True for the four `VEO_3_1_*` variants. Add `I2V_DEFAULT_MODEL = VideoModel.VEO_3_1_LITE` module constant in `api/video.py` (domain).
|
|
56
|
+
- **Typed error class** `ModelModeIncompatibilityError` (new, in `gflow_cli.errors`) wired into `EXIT_CODE_MAP` with **exit code 17** (distinct from Click's exit 2 "usage error" and generic exit 1). Per CLI UX council finding: "semantic model/mode incompatibility known to the domain deserves a typed error."
|
|
57
|
+
- `gflow video i2v` CLI: drop `omni-flash` from the i2v command's `--model` Click `Choice` tuple entirely (cleanest UX per CLI UX council). The `--help` output then lists only valid models; users see the constraint at help time. Note: t2v / r2v keep `omni-flash` in their Choice.
|
|
58
|
+
- `gflow video i2v` CLI: when `--model` omitted → resolve to `I2V_DEFAULT_MODEL` (`veo-lite`). When a deserialized config still names `omni-flash` (e.g. from a stale `--config` JSON), the Click callback raises `ModelModeIncompatibilityError`.
|
|
59
|
+
- **Defense-in-depth transport guard** in `_generate_video_locked`: place **immediately after `_select_video_model` (~L1170)** and BEFORE any `_attach_frame` call (Architect + Performance both flagged this as the right placement — fails before any DOM mutation, no cleanup needed, no `page.reload()`). Guard checks `mode is Mode.I2V and (start_image is not None or end_image is not None) and not model.supports_i2v_interpolation()` → raises `ModelModeIncompatibilityError`. Catches direct `FlowApiClient` callers (gflow-cli-remotion) who bypass Click.
|
|
60
|
+
- **Structlog event** `ui_automation_video.model_mode_rejected` emitted by the transport guard before raising — fields `{model, mode, has_start_image, has_end_image, issue_ref: "#125"}`. Required for e2e assertion per CLI UX council + [[verification-ledger-5-layer]].
|
|
61
|
+
- `--model` Click `help=` text on i2v + i2v command `examples=` corrected.
|
|
62
|
+
- Unit tests for the typed error, Choice-drop, default resolution, transport guard, and structlog assertion — see §6.
|
|
63
|
+
- CHANGELOG entries under both `### Fixed` and `### Changed` (the default-model shift is a Changed behaviour worth surfacing separately).
|
|
64
|
+
- Update issue #125 with the actual root cause and link the PR.
|
|
65
|
+
- Ship two diagnostic probes (`capture_i2v_post_bind_state.py`, `capture_i2v_intercept_submit.py`). **DROP probe v1 (`capture_i2v_upload_dialog_dom.py`)** — it proved a refuted hypothesis; ship-as-doc was post-hoc justification per Devil's Advocate.
|
|
66
|
+
|
|
67
|
+
### Out of scope (deferred — with evidence-based plan)
|
|
68
|
+
|
|
69
|
+
- **r2v + omni-flash compatibility** — Devil's Advocate flagged for in-scope inclusion. Probing r2v requires extending the probe with `--mode references` (different sub-mode, different attach helper `_attach_references`, different endpoint family `batchAsyncGenerateVideoReferenceImages`). Material rewrite. **Decision: file follow-up issue with a one-line probe extension as the first task. Defer scope expansion until evidence in hand.** The plan's transport guard is structured so adding r2v rejection later is a one-line change (`mode is Mode.R2V and not model.supports_r2v(...)`).
|
|
70
|
+
- **omni-flash + start-only i2v** — RESOLVED by probe v5: also routes T2V. Already covered by the in-scope reject-omni-flash-for-any-i2v rule. No longer "unverified strictness."
|
|
71
|
+
- **Full model+mode compatibility matrix** — broader spec; separate work.
|
|
72
|
+
- **Selector-cascade hardening for `_upload_via_open_dialog`** (originally Stage A from the predict review) — no longer needed; probe v1 confirmed the selector works on pt-BR. Drop this scope. (Probe itself dropped from ship list per above.)
|
|
73
|
+
|
|
74
|
+
## 4. Files touched — council-revised
|
|
75
|
+
|
|
76
|
+
| File | Purpose | Change |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| `src/gflow_cli/api/video.py` | Domain | Add `VideoModel.supports_i2v_interpolation()` classmethod. Add `I2V_DEFAULT_MODEL = VideoModel.VEO_3_1_LITE`. Per Architect: "domain invariant, not adapter knowledge — analogous to `Aspect.wire()`." |
|
|
79
|
+
| `src/gflow_cli/errors.py` | Typed error | Add `ModelModeIncompatibilityError(GFlowError)` with `exit_code=17`. Per CLI UX council. |
|
|
80
|
+
| `src/gflow_cli/cli_video.py` | CLI surface | Drop `omni-flash` from i2v `--model` Click `Choice` (cleanest discoverability per CLI UX). Add a Click callback resolving omitted `--model` to `I2V_DEFAULT_MODEL`. Raise `ModelModeIncompatibilityError` if a deserialized config still names `omni-flash` for i2v. Update i2v `--model help=` and command examples. |
|
|
81
|
+
| `src/gflow_cli/api/transports/ui_automation_video.py` | Transport guard | In `_generate_video_locked`, **immediately after `_select_video_model` (~L1170), BEFORE `_attach_frame`**: emit `ui_automation_video.model_mode_rejected` event and raise `ModelModeIncompatibilityError` if `mode is Mode.I2V and (start_image is not None or end_image is not None) and not model.supports_i2v_interpolation()`. Per Architect + Performance: earlier placement = no DOM mutation, no cleanup needed. **No `page.reload()`** — drop the R6 mitigation entirely. |
|
|
82
|
+
| `tests/api/test_video.py` (or sibling) | Unit | `test_supports_i2v_interpolation_matrix` parametrized over all 5 VideoModel variants. `test_i2v_default_model_is_veo_lite`. |
|
|
83
|
+
| `tests/errors/test_exit_codes.py` (or sibling) | Unit | `test_model_mode_incompatibility_error_exit_code_17` + ordering-invariant. |
|
|
84
|
+
| `tests/cli/test_cli_video.py` (or sibling) | Unit | i2v --help no longer lists omni-flash; omitted --model resolves to veo-lite; explicit omni-flash via stale config raises exit 17. |
|
|
85
|
+
| `tests/api/transports/test_ui_automation_video.py` (or sibling) | Unit | `test_transport_rejects_i2v_with_omni_flash` — stubbed request DTO, assert raise + `model_mode_rejected` event captured. |
|
|
86
|
+
| `CHANGELOG.md` | Release note | New `### Fixed` entry (i2v silent T2V regression) + new `### Changed` entry (i2v default model shift to veo-lite). |
|
|
87
|
+
| `scripts/dev/capture_i2v_post_bind_state.py` | Dev tooling | NEW — slot-state regression probe. |
|
|
88
|
+
| `scripts/dev/capture_i2v_intercept_submit.py` | Dev tooling | NEW — definitive zero-credit reproducer (the smoking-gun probe). |
|
|
89
|
+
| ~~`scripts/dev/capture_i2v_upload_dialog_dom.py`~~ | ~~Dev tooling~~ | **DROPPED from ship list** — proved a refuted hypothesis; not maintaining as documentation. |
|
|
90
|
+
|
|
91
|
+
## 5. Implementation steps (in order — each a focused commit) — council-revised
|
|
92
|
+
|
|
93
|
+
1. **Add `ModelModeIncompatibilityError`** to `gflow_cli.errors` + wire into `EXIT_CODE_MAP` with `exit_code=17`. Unit test for ordering-invariant + the new mapping.
|
|
94
|
+
2. **Add `VideoModel.supports_i2v_interpolation()` + `I2V_DEFAULT_MODEL`** in `api/video.py` + unit tests.
|
|
95
|
+
3. **Drop omni-flash from i2v's `--model` Click `Choice`; add resolution callback** in `cli_video.py`. Add `ModelModeIncompatibilityError` raise for the stale-config edge case. Unit tests for both paths.
|
|
96
|
+
4. **Transport guard** at the correct placement (just after `_select_video_model`) in `_generate_video_locked` + structlog event + unit test stubbing the request DTO. Verify no `page.reload()` is added.
|
|
97
|
+
5. **Update `--model help=` text + i2v command examples** in `cli_video.py`.
|
|
98
|
+
6. **CHANGELOG**: `### Fixed` + `### Changed` entries.
|
|
99
|
+
7. **Add the two dev probes** to `scripts/dev/`: `capture_i2v_post_bind_state.py` + `capture_i2v_intercept_submit.py`. Do NOT add `capture_i2v_upload_dialog_dom.py`.
|
|
100
|
+
8. **Update issue #125** with the corrected root cause and link to the PR (in §7 verification, after merge).
|
|
101
|
+
|
|
102
|
+
## 6. Test plan — council-revised
|
|
103
|
+
|
|
104
|
+
### Unit tests
|
|
105
|
+
|
|
106
|
+
- `test_omni_flash_does_not_support_i2v_interpolation`: `VideoModel.OMNI_FLASH.supports_i2v_interpolation() is False`
|
|
107
|
+
- `test_veo_3_1_models_support_i2v_interpolation`: parametrize across the four VEO_3_1_* variants, all return True
|
|
108
|
+
- `test_i2v_default_model_constant`: `I2V_DEFAULT_MODEL is VideoModel.VEO_3_1_LITE`
|
|
109
|
+
- `test_model_mode_incompatibility_error_exit_code_is_17`: `ModelModeIncompatibilityError().exit_code == 17` and the class is registered in `EXIT_CODE_MAP`
|
|
110
|
+
- `test_exit_code_map_ordering_invariant_still_holds` after the new entry (per [[exit-code-map-ordering-invariant-test-pitfall]])
|
|
111
|
+
- `test_i2v_click_choice_excludes_omni_flash`: introspect the i2v command's `--model` Click `Choice` — `"omni-flash" not in choices`. (Compare to t2v Choice which DOES include it.)
|
|
112
|
+
- `test_i2v_cli_resolves_default_to_veo_lite`: `gflow video i2v start.jpg "p" --end-image end.jpg` (no --model) → resolved model in the request DTO is `VideoModel.VEO_3_1_LITE`
|
|
113
|
+
- `test_i2v_cli_rejects_stale_config_with_omni_flash`: a deserialized config JSON pointing at omni-flash for i2v → exits **17** (not 2) with stderr containing "#125" and "veo-lite"
|
|
114
|
+
- `test_transport_raises_on_i2v_with_omni_flash_and_end_image`: invoke `_generate_video_locked` with a stubbed request `(model=OMNI_FLASH, mode=I2V, start_image=Path, end_image=Path)` → raises `ModelModeIncompatibilityError`, structlog captures `model_mode_rejected` event with fields `{model: "omni_flash", mode: "I2V", has_start_image: True, has_end_image: True, issue_ref: "#125"}`. **No DOM mutation must have occurred** — assert no `_attach_frame` call fired (via mock).
|
|
115
|
+
- `test_transport_raises_on_i2v_with_omni_flash_and_start_only`: same shape but `end_image=None`, `start_image=Path` — still raises (omni-flash rejected for any i2v ref, per probe evidence).
|
|
116
|
+
- `test_transport_does_NOT_raise_on_t2v_with_omni_flash`: pure t2v + omni-flash is a valid combination — guard must NOT fire.
|
|
117
|
+
|
|
118
|
+
### Integration tests
|
|
119
|
+
|
|
120
|
+
- BDD scenario: "user runs i2v with default model" → command resolves to veo-lite, no Flow interaction. Assert `structlog` shows `model_mode_rejected` is NOT emitted.
|
|
121
|
+
- BDD scenario: "in-process API caller (e.g. flow_workflow.py shape) passes `model=OMNI_FLASH, mode=I2V, start_image=Path` to `FlowApiClient.generate_video`" → raises `ModelModeIncompatibilityError`, exit code 17. **This is the safety net for gflow-cli-remotion-style consumers.**
|
|
122
|
+
- Audit existing i2v integration tests: any fixture using omni-flash for i2v must be updated to a Veo 3.1 model.
|
|
123
|
+
|
|
124
|
+
### Live e2e (1 paid credit)
|
|
125
|
+
|
|
126
|
+
- Re-run probe v5 (`capture_i2v_intercept_submit.py --model veo-lite ...`) zero-credit sanity check — captured URL must still be `StartAndEndImage` with bound mediaIds.
|
|
127
|
+
- Then a live `gflow video i2v 01-t2i.jpg "<tightened stickman motion prompt>" --end-image 02-i2i.jpg --model veo-lite --aspect 9:16 --profile promo-denon82` → expect:
|
|
128
|
+
- structured log `ui_automation_video.generate_captured` event with `url=batchAsyncGenerateVideoStartAndEndImage` and `image_inputs.startImage` + `image_inputs.endImage` non-null
|
|
129
|
+
- **assert structured log does NOT contain `ui_automation_video.model_mode_rejected`** (positive verification that the new guard didn't false-fire on a valid combination)
|
|
130
|
+
- output mp4 visually: 2D ink line-art stickman starting at desk (matches 01-t2i.jpg), interpolating to arms-raised at sunrise (matches 02-i2i.jpg)
|
|
131
|
+
- 5-layer verification ledger per memory [[verification-ledger-5-layer]]: file count, magic bytes (mp4 signature), Pillow dims (720×1280), structlog invariants (above), user gallery confirmation.
|
|
132
|
+
|
|
133
|
+
## 7. Verification ladder (definition of done) — council-revised
|
|
134
|
+
|
|
135
|
+
- [ ] `ruff format --check` + `ruff check` clean on `src/gflow_cli/{cli_video,errors,api/video,api/transports/ui_automation_video}.py` and the two dev probe scripts shipping.
|
|
136
|
+
- [ ] `pyright` clean on the same scoped paths.
|
|
137
|
+
- [ ] All new unit tests pass (see §6).
|
|
138
|
+
- [ ] Scoped pytest of `tests/cli/` + `tests/api/` + `tests/api/transports/` + `tests/errors/` passes (full sweep deferred to CI per [[full-test-suite-ooms]]).
|
|
139
|
+
- [ ] BDD/integration tests pass.
|
|
140
|
+
- [ ] **Exit-code-map ordering-invariant test passes** (per [[exit-code-map-ordering-invariant-test-pitfall]]) — adding code 17 must not invert any prior subclass-relation invariant.
|
|
141
|
+
- [ ] Probe v5 re-run with `--model veo-lite` still produces `StartAndEndImage` URL with bound mediaIds (zero credit).
|
|
142
|
+
- [ ] Probe v5 re-run with `--model omni-flash --start-only` still produces T2V (zero credit — proves the rejection is still warranted).
|
|
143
|
+
- [ ] 1 paid live e2e i2v run completes; structured log shows `generate_captured.url=batchAsyncGenerateVideoStartAndEndImage` with non-null mediaIds AND `model_mode_rejected` event is NOT emitted.
|
|
144
|
+
- [ ] User watches the output mp4 and verbally confirms it's a 2D ink line-art stickman desk → sunrise scene matching the refs.
|
|
145
|
+
- [ ] Issue #125 comment thread updated with the actual root cause + closed by PR merge.
|
|
146
|
+
- [ ] CHANGELOG entries present under `[Unreleased]` — both `### Fixed` and `### Changed`.
|
|
147
|
+
|
|
148
|
+
## 8. Risks + mitigations
|
|
149
|
+
|
|
150
|
+
| Risk | Severity | Mitigation |
|
|
151
|
+
|---|---|---|
|
|
152
|
+
| R1: Changing default model silently surprises users who already had a working incantation | LOW — prior incantation was broken (T2V output); making it work correctly is a strict improvement | None needed beyond clear CHANGELOG note |
|
|
153
|
+
| R2: veo-lite has different cost/quality than omni-flash | LOW — both are tier-one lite models; veo-3.1-lite cost is documented in Flow's UI per `MEDIA_GENERATION_PAYGATE_TIER: PAYGATE_TIER_ONE` | Document in --model help text |
|
|
154
|
+
| R3: omni-flash + start-only i2v might actually work (unverified) | MEDIUM — if it does work, our strict rejection blocks a valid combination | Conservative reject in this PR; reverse with probe evidence in a follow-up if proven |
|
|
155
|
+
| R4: r2v + omni-flash has the same silent-drop pathology | MEDIUM — separate UI surface, separate ticket needed | Out of scope; file follow-up issue with link from #125 |
|
|
156
|
+
| R5: Hidden in-process API callers (scripts using `FlowApiClient` directly like `gflow-cli-remotion/flow_workflow.py`) bypass the CLI validation | MEDIUM | The transport guard in `_generate_video_locked` is the safety net for these callers |
|
|
157
|
+
| ~~R6: pre-submit guard raises but the page is left in a dirty state for the pool~~ | ~~LOW~~ | **DROPPED per Performance council review.** Guard now placed at L1170 (immediately after `_select_video_model`, BEFORE any `_attach_frame`) — fires before any DOM-state mutation, no Page cleanup needed, no `page.reload()`. Architect concurred ("earlier-fail is cleaner than dirty-state cleanup"). |
|
|
158
|
+
|
|
159
|
+
## 9. Rollback
|
|
160
|
+
|
|
161
|
+
- Revert the PR as a single commit-range. No DB migrations, no settings changes, no state mutations.
|
|
162
|
+
- The transport guard fails-closed: if a user with cached venv hits the guard on a stale config, they get a clear error pointing at #125 with remediation. No silent regression.
|
|
163
|
+
|
|
164
|
+
## 10. CHANGELOG entries — council-revised (two sections)
|
|
165
|
+
|
|
166
|
+
```markdown
|
|
167
|
+
### Fixed
|
|
168
|
+
|
|
169
|
+
- `gflow video i2v` silently routed every call to the T2V endpoint with
|
|
170
|
+
`image_inputs: null` when the model was `omni-flash` (Flow's last-used
|
|
171
|
+
default in most sessions). Flow's frontend rejects omni-flash + frame
|
|
172
|
+
refs and falls back to text-only generation, but the rejection is
|
|
173
|
+
invisible to the client — every i2v paid run on v0.10.0 burned a
|
|
174
|
+
credit for a pure text-to-video generation that ignored the supplied
|
|
175
|
+
start/end frames. Issue #125. Fix: omni-flash dropped from the i2v
|
|
176
|
+
`--model` Click `Choice` entirely; a defense-in-depth transport guard
|
|
177
|
+
in `_generate_video_locked` raises `ModelModeIncompatibilityError`
|
|
178
|
+
(exit code 17) for direct `FlowApiClient` callers that bypass the CLI.
|
|
179
|
+
|
|
180
|
+
### Changed
|
|
181
|
+
|
|
182
|
+
- `gflow video i2v` default model is now `veo-lite` (was: inherit
|
|
183
|
+
Flow's last-used, which was typically `omni-flash` — see Fixed). The
|
|
184
|
+
veo-3.1 family is the only model line that supports i2v
|
|
185
|
+
interpolation; omni-flash is now correctly rejected for any i2v
|
|
186
|
+
invocation (start-only or start+end). Explicit `--model omni-flash`
|
|
187
|
+
for `gflow video t2v` and `gflow video r2v` remains valid.
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## 11. Migration / backward compat
|
|
191
|
+
|
|
192
|
+
- No breaking config or env-var changes.
|
|
193
|
+
- v0.10.0 users running `gflow video i2v ... --end-image ...` without explicit `--model` previously got silent T2V output; they now get correct interpolation (silent improvement, no surprise).
|
|
194
|
+
- v0.10.0 users running `gflow video i2v ... --end-image ... --model omni-flash` previously got silent T2V; they now get a clear error with `gflow video i2v ... --end-image ... --model veo-lite` as the remediation.
|
|
195
|
+
- BREAKING for: nobody. The prior behavior was a silent bug.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Appendix: probe scripts
|
|
200
|
+
|
|
201
|
+
All zero-credit. Only two ship in this PR per Devil's Advocate review (probe v1 dropped — proved a refuted hypothesis, no future-locale-regression value).
|
|
202
|
+
|
|
203
|
+
| Probe | What it proved | Ships? |
|
|
204
|
+
|---|---|---|
|
|
205
|
+
| `capture_i2v_upload_dialog_dom.py` | "Incluir no comando" pt-BR button matches the production `add_btn` selector — selector cascade is correct (REFUTED original hypothesis). | **NO** — proved a refuted hypothesis; not maintaining as documentation. |
|
|
206
|
+
| `capture_i2v_post_bind_state.py` | `FRAME_SLOTS_STRUCT.count()` transitions 2 → 1 → 0 after binds; submit button is unambiguous (single arrow_forward "Criar" button); slots stay bound after prompt typing. | **YES** — useful future probe for slot-state regressions. |
|
|
207
|
+
| `capture_i2v_intercept_submit.py` | Intercepts the submit XHR via `page.route(..., abort)` and inspects the request body. omni-flash → T2V with null images (both start+end and start-only); veo-lite → StartAndEndImage with populated mediaIds. **This is the definitive reproducer.** | **YES** — definitive regression probe for future model/mode work. |
|