gflow-cli 0.10.0__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/release.md +241 -0
- gflow_cli-0.11.0/.planning/issue-125-fix.md +207 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/AGENTS.md +17 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/CHANGELOG.md +62 -1
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/CLAUDE.md +14 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/KNOWN_ISSUES.md +14 -10
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/PKG-INFO +4 -2
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/PLAN.md +2 -2
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/README.md +3 -1
- gflow_cli-0.11.0/docs/DEMOS.md +47 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/INDEX.md +7 -1
- gflow_cli-0.11.0/docs/LIVE_VERIFICATION_v0.11.0.md +100 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/PROJECT_STATUS.md +5 -2
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/USAGE.md +9 -0
- gflow_cli-0.11.0/docs/assets/demo-split-pf.gif +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/examples/README.md +4 -0
- gflow_cli-0.11.0/examples/workflow_chain.py +314 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/pyproject.toml +1 -1
- 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/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.10.0 → gflow_cli-0.11.0}/skills/README.md +31 -1
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/skills/gflow-cli/SKILL.md +32 -1
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/skills/pr-council-review/SKILL.md +1 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/skills/predict/SKILL.md +1 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/__init__.py +1 -1
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/ui_automation.py +37 -27
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/ui_automation_video.py +283 -26
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/video.py +23 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/cli_data.py +6 -3
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/cli_video.py +36 -6
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/recorder.py +14 -21
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/errors.py +59 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_video.py +24 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_ui_automation.py +442 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_ui_automation_video.py +290 -2
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_cli_video.py +107 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_transports_e2e.py +144 -2
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_errors.py +26 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/uv.lock +1 -1
- gflow_cli-0.10.0/.claude/commands/gflow/release.md +0 -168
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/README.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/branch-review.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/changelog.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/check.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/doc-review.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/known-issues.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/plan.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/pr-council-review.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/predict.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/scenario.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.continue-here.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.env.template +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.gitattributes +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.github/CODEOWNERS +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.github/copilot-instructions.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.github/dependabot.yml +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.github/workflows/ci.yml +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.github/workflows/external-pr-triage.yml +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.github/workflows/release.yml +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.gitignore +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.gitleaks.toml +0 -0
- {gflow_cli-0.10.0 → 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.10.0 → gflow_cli-0.11.0}/.planning/todos/pending/pr-38-review.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.pre-commit-config.yaml +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.secrets.baseline +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/CONFIGURATION.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/CONTRIBUTING.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/DISCLAIMER.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/GEMINI.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/LICENSE +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/RELEASE.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/ROADMAP.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/conftest.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docker-compose.yml +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/AGENT_GUIDE.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/ARCHITECTURE.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/AUTHENTICATION.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/CONFIGURATION.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/DATA_LAYER.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/DEBUGGING.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/DEVELOPMENT.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/E2E_TESTING.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/EXTERNAL_STORAGE.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/GITHUB.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_data_layer.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_image_batch.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_v0.10.0.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_v0.7.0.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_v0.8.1.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_v0.9.0.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_v0.9.1.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_video_download.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/SECURITY.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/USER_GUIDE.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/assets/example-run.gif +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/2026-05-17-issue-15-handover.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-09-image-mvp-orchestration.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-09-image-mvp.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-09-video-mvp-orchestration.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-09-video-mvp.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-10-phase-4-hardening-orchestration.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-10-phase-4-hardening.md +0 -0
- {gflow_cli-0.10.0 → 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.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_FINAL_ARCH.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_FINAL_SEC_UX.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_CODE.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_GEMINI.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_SECURITY.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/IMPLEMENTATION_REVIEW_PYTHON.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/IMPLEMENTATION_REVIEW_SECURITY.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_CODE.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_FOLLOWUP.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_PLANNER.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_SECURITY.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_SECURITY_FOLLOWUP.md +0 -0
- {gflow_cli-0.10.0 → 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.10.0 → 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.10.0 → 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.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/PLAN.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/orchestration.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-17-e2e-test-coverage.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-17-issue-15-auth-verification-fix.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-17-issue-15-i2v-bearer-auth.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-17-issue-15-orchestration.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-18-video-phase0-submit-spike.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-19-video-phase-a-execution-state.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-19-video-phase-a-orchestration.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-19-video-phase-a-t2v.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-20-video-download-t2v-cli.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-21-multi-image-prompt-orchestration.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-21-multi-image-prompt.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-22-pr-38-review.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-22-stay-mounted-batch-session-plan.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-23-locale-agnostic-selectors.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-24-data-layer.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-10-phase-4-hardening-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-14-shell-multi-prompt-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-15-auth-login-real-chrome-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-17-e2e-test-coverage-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-17-i2v-uploadimage-401-bearer-auth-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-17-issue-15-auth-verification-fix-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-17-issue-15-root-cause-findings.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-18-ui-automation-video-generation-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-21-multi-image-prompt-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-22-pr-38-review-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-22-stay-mounted-batch-session-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-23-locale-agnostic-selectors.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-23-readme-v0.8.1-refresh-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-24-data-layer-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-27-public-event-surface-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/verifications/2026-05-11-phase-4-stage-g.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/examples/batch_from_config.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/examples/multi_prompt_t2i.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/examples/sample_config.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/examples/sample_prompts.txt +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/examples/single_image_t2i.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/llms.txt +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/README.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/01_upload_image.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/02_batchAsyncGenerateVideoText.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/04_archive_workflow.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/05_createProject.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/06_batchGenerateImages.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/07_batchGenerateImages_seeded.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/08_batchAsyncGenerateVideoStartAndEndImage.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/09_batchAsyncGenerateVideoReferenceImages.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/10_batchCheckAsyncVideoGenerationStatus_successful.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/11_batchCheckAsyncVideoGenerationStatus_failed.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/ci/check_doc_links.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/ci/check_repo_hygiene.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/debug_editor.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/debug_gen_settings.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/debug_settings.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/dev/active_plan.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/dev/capture_i2v_frame_slots_dom.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/dev/capture_image_add_media_dom.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/dev/capture_locale_invariants.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/dev/cdp_drive_and_probe.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/dev/monitor_pr_38.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/diag_capture_flow_traffic.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/diag_recaptcha_mint.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/record_demo.ps1 +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/smoke_image.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/smoke_real_chrome_image.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/smoke_video_editor.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/smoke_worker_style.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/verify_chrome_auth_viability.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/skills/scenario/SKILL.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/sonar-project.properties +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/__main__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/_cli_helpers.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/_retry.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/client.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/dto.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/image.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/recaptcha.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/routes.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/_common.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/_fingerprint.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/base.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/experimental/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/experimental/bearer.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/experimental/evaluate_fetch.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/experimental/sapisidhash.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/auth/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/auth/base.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/auth/factory.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/auth/internal_chromium.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/auth/real_chrome.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/auth/strategies.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/auth/verification.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/browser_manager.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/cli.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/cli_image.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/cli_models.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/cli_run.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/config.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/migrations/0001_initial.sql +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/migrations/0002_add_cloud_storage.sql +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/migrations/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/models.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/queries.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/redaction.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/repository.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/store.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/exceptions.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/image_batch.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/json_output.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/manifest.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/observability.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/paths.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/profile_store.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/storage.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tasks/lessons.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/test_assets/sample_batch.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/test_assets/sample_batch.tsv +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/test_assets/sample_batch_invalid.tsv +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_client.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_client_image.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_concurrency.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_dto.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_image.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_image_dto.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_recaptcha.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_retry.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_routes.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_base.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_bearer.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_common.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_evaluate_fetch.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_factory.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_fingerprint.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_sapisidhash.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_transport_timeout.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_ui_automation_batch.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_ui_automation_image_mode.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/auth/strategies/test_factory.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/auth/strategies/test_strategies.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/auth/test_verification.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_cli_auth_list.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_cli_data.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_cli_image.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_cli_image_seed_removed.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_cli_models.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_cli_run.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_error_handling.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_helpers.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_t2i_multi_prompt.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/conftest.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/data/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/data/test_packaging.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/data/test_recorder.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/data/test_redaction.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/data/test_repository.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/data/test_settings_and_errors.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/data/test_store_migrations.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/conftest.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_auth_verification_e2e.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_data_layer_e2e.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_image_batch_e2e.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_image_i2i_ref_cap_e2e.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_json_output_e2e.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_locale_selectors_e2e.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_video_r2v_ref_cap_e2e.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_video_t2v_e2e.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/auth.feature +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/auth_login.feature +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/conftest.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/image.feature +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/test_auth_login_steps.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/test_auth_steps.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/test_image_steps.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/test_step_collision_guard.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/fixtures/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/fixtures/seeded_catalog.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/image_batch/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/image_batch/test_image_manifest.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/image_batch/test_observability_events.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/integration/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/integration/conftest.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/integration/constants.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/integration/test_storage_gcs.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/integration/test_storage_s3.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/scripts/test_capture_locale_invariants.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/smoke/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/smoke/test_profile_account_smoke.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/smoke/test_real_flow.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_auth.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_browser_manager.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_cli_data.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_config.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_conftest_isolation.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_data_queries.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_documentation_gate.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_json_output.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_manifest.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_marker_registry.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_observability.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_paths.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_profile_store.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_smoke.py +0 -0
|
@@ -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,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. |
|
|
@@ -66,6 +66,23 @@ Or invoke the wrapper: `/gflow:check`.
|
|
|
66
66
|
- Run `/gflow:check` (or the Impeccable Routine) before every commit.
|
|
67
67
|
- All releases require a signed annotated tag (`git tag -s vX.Y.Z`); CI rejects unsigned tags.
|
|
68
68
|
|
|
69
|
+
## Skills reference (cross-tool)
|
|
70
|
+
|
|
71
|
+
The `skills/` directory ships installable agent skill docs in plain Markdown with YAML frontmatter. Any agent can consume them directly:
|
|
72
|
+
|
|
73
|
+
| Skill | Path | When to load |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| `gflow-cli` | [`skills/gflow-cli/SKILL.md`](skills/gflow-cli/SKILL.md) | User wants to run any `gflow` command — auth, T2V, I2V, T2I, I2I, batch |
|
|
76
|
+
| `predict` | [`skills/predict/SKILL.md`](skills/predict/SKILL.md) | Pre-implementation adversarial analysis before any high-stakes change |
|
|
77
|
+
| `scenario` | [`skills/scenario/SKILL.md`](skills/scenario/SKILL.md) | Edge-case explorer after a predict GO/CAUTION |
|
|
78
|
+
| `pr-council-review` | [`skills/pr-council-review/SKILL.md`](skills/pr-council-review/SKILL.md) | Multi-dimensional PR council review |
|
|
79
|
+
|
|
80
|
+
**Cursor / Aider / Codex / Gemini CLI:** paste or include the relevant `SKILL.md` in your system context.
|
|
81
|
+
**Claude Code:** symlink `skills/gflow-cli` to `~/.claude/skills/gflow-cli` to register the skill; the `/gflow:` slash commands (in `.claude/commands/gflow/`) are auto-discovered from the project directory.
|
|
82
|
+
**Custom agents:** fetch `skills/gflow-cli/SKILL.md` into your knowledge base before answering gflow questions.
|
|
83
|
+
|
|
84
|
+
The SkillOpt harness at `scripts/dev/skillopt/` measures how accurately each skill guides an agent, and supports multiple providers (Anthropic, OpenAI-compat, Gemini, local models). See [`scripts/dev/skillopt/README.md`](scripts/dev/skillopt/README.md).
|
|
85
|
+
|
|
69
86
|
## Where to look next
|
|
70
87
|
|
|
71
88
|
- **Architecture & target shape** → [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
|
@@ -7,6 +7,66 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.11.0] — 2026-05-31
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **`gflow video i2v` default model is now `veo-lite`** (was: inherit Flow's
|
|
15
|
+
last-used model, which was typically `omni-flash`). The Veo 3.1 family is
|
|
16
|
+
the only model line that supports i2v interpolation; `omni-flash` is now
|
|
17
|
+
rejected for any i2v invocation (start-only or start+end) and has been
|
|
18
|
+
removed from the i2v `--model` choices. Because `--duration 10` is
|
|
19
|
+
omni-flash-only, the i2v `--duration` choices are now `[4|6|8]`. `omni-flash`
|
|
20
|
+
(and `--duration 10`) remain valid for `gflow video t2v` and `gflow video r2v`.
|
|
21
|
+
See issue #125.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- **`gflow video i2v` silently produced text-to-video output, ignoring the
|
|
26
|
+
start/end frames (issue #125).** When the model was `omni-flash` (Flow's
|
|
27
|
+
last-used default in most sessions), Flow's frontend dropped the bound
|
|
28
|
+
start/end frame references at submit time and routed every call to
|
|
29
|
+
`batchAsyncGenerateVideoText` with `image_inputs: null` — charging a credit
|
|
30
|
+
for a pure text-to-video generation that had no visual relationship to the
|
|
31
|
+
supplied frames. **Every i2v paid run on v0.10.0 before this fix produced
|
|
32
|
+
T2V output regardless of the start/end frames.** Fix: `omni-flash` is
|
|
33
|
+
dropped from the i2v `--model` choices and the i2v default is now `veo-lite`;
|
|
34
|
+
a defense-in-depth transport guard raises `ModelModeIncompatibilityError`
|
|
35
|
+
(exit code 17) for direct `FlowApiClient` callers that bypass the CLI.
|
|
36
|
+
|
|
37
|
+
- **`gflow video i2v` could still route to T2V even with a valid Veo model,
|
|
38
|
+
because the model-picker option `Veo 3.1 - Lite` was never selected (issue
|
|
39
|
+
#125, second path).** The picker selector was an exact-match
|
|
40
|
+
(`:text-is('volume_upVeo 3.1 - Lite')`) that hardcoded a Material Symbols
|
|
41
|
+
icon-ligature prefix; when it missed, `_select_video_model` warned and
|
|
42
|
+
continued, leaving Flow on `omni-flash` → the frames were dropped to T2V.
|
|
43
|
+
Fixes: (1) the selector is now a robust substring match
|
|
44
|
+
(`:has-text('Veo 3.1 - Lite'):not(:has-text('[Lower Priority]'))`); (2) for
|
|
45
|
+
i2v, a model-select miss is now FATAL — `_select_video_model(required=True)`
|
|
46
|
+
retries the picker then raises `VideoModelSelectionError` (exit code 18)
|
|
47
|
+
*before* any frame attach or submit, spending no credit; (3) a post-submit
|
|
48
|
+
backstop raises `WireFormatError` if an i2v request is still observed routing
|
|
49
|
+
to the T2V endpoint, so a "successful" T2V is never reported as i2v.
|
|
50
|
+
|
|
51
|
+
- **Create-project generation failing when Flow's "Agent" composer mode is active.**
|
|
52
|
+
Flow's newer editor adds an Agent toggle next to the prompt box; when it is on,
|
|
53
|
+
the media-generation panel (the `crop_*` settings trigger, Image/Video mode
|
|
54
|
+
tablist, and count/model controls) is removed from the DOM, so the UI-automation
|
|
55
|
+
transport raised "mode-switch dropdown trigger not found". `_switch_to_image_mode`
|
|
56
|
+
and `_switch_to_video_mode` now call `_exit_agent_mode()` first, which re-mounts
|
|
57
|
+
the panel by clicking the toggle off. Detection is locale-invariant and uses no
|
|
58
|
+
UI text and no `aria-` attribute (`button:has(span.content)` plus the absence of
|
|
59
|
+
the locale-stable `crop_*` trigger), so it works in every Flow UI language.
|
|
60
|
+
|
|
61
|
+
- **`gflow image t2i` / `i2i` model selection hardened for non-English Flow UIs
|
|
62
|
+
(issue #94).** `IMAGE_MODEL_OPTION_SELECTORS` is now a selector *cascade*
|
|
63
|
+
(consistent with every other selector group) instead of a single exact-match
|
|
64
|
+
string, so `_select_image_model` no longer silently fails to select the
|
|
65
|
+
requested model when Flow's menu markup shifts. The redundant `--lang=en-US`
|
|
66
|
+
Chromium launch arg was removed — Flow's branded model names ("Nano Banana 2",
|
|
67
|
+
"Nano Banana Pro", "Imagen 4") are not localised and `FLOW_URL`'s `?hl=en`
|
|
68
|
+
already locks the SPA to English, so the override was a no-op.
|
|
69
|
+
|
|
10
70
|
## [0.10.0] — 2026-05-29
|
|
11
71
|
|
|
12
72
|
### Fixed
|
|
@@ -1209,7 +1269,8 @@ shell-script template that branches on these codes.
|
|
|
1209
1269
|
|
|
1210
1270
|
First skeleton. Not functional end-to-end yet.
|
|
1211
1271
|
|
|
1212
|
-
[Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.
|
|
1272
|
+
[Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.11.0...HEAD
|
|
1273
|
+
[0.11.0]: https://github.com/ffroliva/gflow-cli/compare/v0.10.0...v0.11.0
|
|
1213
1274
|
[0.10.0]: https://github.com/ffroliva/gflow-cli/compare/v0.9.1...v0.10.0
|
|
1214
1275
|
[0.9.1]: https://github.com/ffroliva/gflow-cli/compare/v0.9.0...v0.9.1
|
|
1215
1276
|
[0.9.0]: https://github.com/ffroliva/gflow-cli/compare/v0.8.1...v0.9.0
|
|
@@ -22,6 +22,20 @@
|
|
|
22
22
|
- Skills under `skills/` are auto-discoverable; `gflow-cli` ships its own at [`skills/gflow-cli/SKILL.md`](skills/gflow-cli/SKILL.md).
|
|
23
23
|
- Auto-memory at `~/.claude/projects/C--development-github-gflow-cli/memory/MEMORY.md` carries cross-session feedback and project state.
|
|
24
24
|
|
|
25
|
+
## MCP GitHub tool — PR body rule (non-negotiable)
|
|
26
|
+
|
|
27
|
+
When calling `mcp__github__create_pull_request` or `mcp__github__update_pull_request`, the `body` parameter **must be a plain string**. Shell heredoc syntax (`$(cat <<'EOF' ... EOF)`) is **never valid** here — MCP tool parameters are JSON, not shell; the heredoc is not evaluated and appears literally in the PR description.
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
# WRONG — produces literal "$(cat <<'EOF'" in the PR body:
|
|
31
|
+
body: "$(cat <<'EOF'\n## Summary\n...\nEOF\n)"
|
|
32
|
+
|
|
33
|
+
# CORRECT — plain multiline string:
|
|
34
|
+
body: "## Summary\n\n- Item 1\n- Item 2\n\n## Test plan\n- [ ] ..."
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The heredoc pattern (`$(cat <<'EOF' ... EOF)`) is only valid inside a `Bash` tool call because the **shell** evaluates it there. In every MCP tool parameter it is a literal string. This mistake has recurred across multiple PRs — treat this rule as a hard blocker before every PR creation or update.
|
|
38
|
+
|
|
25
39
|
## Active phase
|
|
26
40
|
|
|
27
41
|
See [PLAN.md](PLAN.md) or run `/gflow:plan` for the current detailed plan.
|
|
@@ -315,15 +315,18 @@ issue and not blocked by any code change in this repo.
|
|
|
315
315
|
|
|
316
316
|
---
|
|
317
317
|
|
|
318
|
-
### `UiAutomationTransport` selectors
|
|
318
|
+
### `UiAutomationTransport` selectors locale-agnostic — issue #24 Phase 5 complete
|
|
319
319
|
|
|
320
|
-
- **Status:**
|
|
320
|
+
- **Status:** Resolved (pending owner live e2e on non-EN profile) · **Severity:** Low · **Tracking:** [issue #24](https://github.com/ffroliva/gflow-cli/issues/24), [issue #94](https://github.com/ffroliva/gflow-cli/issues/94)
|
|
321
321
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
322
|
+
`--lang=en-US` removed in PR #127 (2026-05-30). All selector groups now use
|
|
323
|
+
locale-stable anchors: `IMAGE_MODEL_OPTION_SELECTORS` and
|
|
324
|
+
`VIDEO_MODEL_OPTION_SELECTORS` converted to `dict[Model, tuple[str, ...]]`
|
|
325
|
+
cascade structure; branded product names ("Nano Banana 2", "Nano Banana Pro",
|
|
326
|
+
"Imagen 4", "Veo 3.1 - *", "Omni Flash") are confirmed locale-stable
|
|
327
|
+
Google-branded identifiers. Locale is controlled by the `locale=locale_env`
|
|
328
|
+
Playwright kwarg (persists across all in-session navigations). Full resolution
|
|
329
|
+
gate: live e2e with `gflow image t2i` (each model) on a non-EN Chrome profile.
|
|
327
330
|
|
|
328
331
|
**Phase 2 progress (2026-05-25, develop / post-v0.8.1, unreleased):**
|
|
329
332
|
|
|
@@ -402,9 +405,10 @@ issue and not blocked by any code change in this repo.
|
|
|
402
405
|
lead and cover the common path, so these are maintenance debt rather than
|
|
403
406
|
active blockers).
|
|
404
407
|
|
|
405
|
-
**
|
|
406
|
-
(`GFLOW_CLI_LOCALE=<non-EN>`
|
|
407
|
-
|
|
408
|
+
**Remaining gate:** live e2e with `gflow image t2i --model <each>` on a non-EN
|
|
409
|
+
Chrome profile (`GFLOW_CLI_LOCALE=<non-EN>`) to confirm model picker resolves
|
|
410
|
+
correctly without `--lang=en-US`. `--lang=en-US` has been removed (PR #127);
|
|
411
|
+
`locale=locale_env` Playwright kwarg provides locale continuity across navigations.
|
|
408
412
|
|
|
409
413
|
**Workaround:** with Phase 2 changes, most locales are handled automatically.
|
|
410
414
|
For locales outside the 14 covered by `_ONBOARDING_TEXT_SELECTORS`, ARIA-based
|