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.
Files changed (337) hide show
  1. gflow_cli-0.11.0/.claude/commands/gflow/release.md +241 -0
  2. gflow_cli-0.11.0/.planning/issue-125-fix.md +207 -0
  3. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/AGENTS.md +17 -0
  4. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/CHANGELOG.md +62 -1
  5. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/CLAUDE.md +14 -0
  6. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/KNOWN_ISSUES.md +14 -10
  7. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/PKG-INFO +4 -2
  8. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/PLAN.md +2 -2
  9. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/README.md +3 -1
  10. gflow_cli-0.11.0/docs/DEMOS.md +47 -0
  11. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/INDEX.md +7 -1
  12. gflow_cli-0.11.0/docs/LIVE_VERIFICATION_v0.11.0.md +100 -0
  13. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/PROJECT_STATUS.md +5 -2
  14. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/USAGE.md +9 -0
  15. gflow_cli-0.11.0/docs/assets/demo-split-pf.gif +0 -0
  16. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/examples/README.md +4 -0
  17. gflow_cli-0.11.0/examples/workflow_chain.py +314 -0
  18. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/pyproject.toml +1 -1
  19. gflow_cli-0.11.0/scripts/dev/capture_i2v_intercept_submit.py +262 -0
  20. gflow_cli-0.11.0/scripts/dev/capture_i2v_model_select_repro.py +104 -0
  21. gflow_cli-0.11.0/scripts/dev/capture_i2v_post_bind_state.py +288 -0
  22. gflow_cli-0.11.0/scripts/dev/skillopt/README.md +106 -0
  23. gflow_cli-0.11.0/scripts/dev/skillopt/harness.py +365 -0
  24. gflow_cli-0.11.0/scripts/dev/skillopt/tasks.json +242 -0
  25. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/skills/README.md +31 -1
  26. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/skills/gflow-cli/SKILL.md +32 -1
  27. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/skills/pr-council-review/SKILL.md +1 -0
  28. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/skills/predict/SKILL.md +1 -0
  29. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/__init__.py +1 -1
  30. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/ui_automation.py +37 -27
  31. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/ui_automation_video.py +283 -26
  32. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/video.py +23 -0
  33. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/cli_data.py +6 -3
  34. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/cli_video.py +36 -6
  35. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/recorder.py +14 -21
  36. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/errors.py +59 -0
  37. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_video.py +24 -0
  38. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_ui_automation.py +442 -0
  39. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_ui_automation_video.py +290 -2
  40. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_cli_video.py +107 -0
  41. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_transports_e2e.py +144 -2
  42. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_errors.py +26 -0
  43. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/uv.lock +1 -1
  44. gflow_cli-0.10.0/.claude/commands/gflow/release.md +0 -168
  45. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/README.md +0 -0
  46. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/branch-review.md +0 -0
  47. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/changelog.md +0 -0
  48. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/check.md +0 -0
  49. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/doc-review.md +0 -0
  50. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/known-issues.md +0 -0
  51. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/plan.md +0 -0
  52. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/pr-council-review.md +0 -0
  53. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/predict.md +0 -0
  54. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.claude/commands/gflow/scenario.md +0 -0
  55. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.continue-here.md +0 -0
  56. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.env.template +0 -0
  57. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.gitattributes +0 -0
  58. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.github/CODEOWNERS +0 -0
  59. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  60. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.github/copilot-instructions.md +0 -0
  61. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.github/dependabot.yml +0 -0
  62. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.github/workflows/ci.yml +0 -0
  63. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.github/workflows/external-pr-triage.yml +0 -0
  64. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.github/workflows/release.yml +0 -0
  65. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.gitignore +0 -0
  66. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.gitleaks.toml +0 -0
  67. {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
  68. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.planning/todos/pending/pr-38-review.md +0 -0
  69. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.pre-commit-config.yaml +0 -0
  70. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/.secrets.baseline +0 -0
  71. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/CONFIGURATION.md +0 -0
  72. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/CONTRIBUTING.md +0 -0
  73. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/DISCLAIMER.md +0 -0
  74. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/GEMINI.md +0 -0
  75. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/LICENSE +0 -0
  76. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/RELEASE.md +0 -0
  77. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/ROADMAP.md +0 -0
  78. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/conftest.py +0 -0
  79. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docker-compose.yml +0 -0
  80. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/AGENT_GUIDE.md +0 -0
  81. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/ARCHITECTURE.md +0 -0
  82. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/AUTHENTICATION.md +0 -0
  83. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/CONFIGURATION.md +0 -0
  84. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/DATA_LAYER.md +0 -0
  85. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/DEBUGGING.md +0 -0
  86. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/DEVELOPMENT.md +0 -0
  87. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/E2E_TESTING.md +0 -0
  88. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/EXTERNAL_STORAGE.md +0 -0
  89. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/GITHUB.md +0 -0
  90. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_data_layer.md +0 -0
  91. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_image_batch.md +0 -0
  92. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_v0.10.0.md +0 -0
  93. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_v0.7.0.md +0 -0
  94. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_v0.8.1.md +0 -0
  95. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_v0.9.0.md +0 -0
  96. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_v0.9.1.md +0 -0
  97. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/LIVE_VERIFICATION_video_download.md +0 -0
  98. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/SECURITY.md +0 -0
  99. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/USER_GUIDE.md +0 -0
  100. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/assets/example-run.gif +0 -0
  101. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/2026-05-17-issue-15-handover.md +0 -0
  102. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-09-image-mvp-orchestration.md +0 -0
  103. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-09-image-mvp.md +0 -0
  104. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-09-video-mvp-orchestration.md +0 -0
  105. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-09-video-mvp.md +0 -0
  106. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-10-phase-4-hardening-orchestration.md +0 -0
  107. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-10-phase-4-hardening.md +0 -0
  108. {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
  109. {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
  110. {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
  111. {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
  112. {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
  113. {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
  114. {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
  115. {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
  116. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN.md +0 -0
  117. {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
  118. {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
  119. {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
  120. {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
  121. {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
  122. {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
  123. {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
  124. {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
  125. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/PLAN.md +0 -0
  126. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/orchestration.md +0 -0
  127. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-17-e2e-test-coverage.md +0 -0
  128. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-17-issue-15-auth-verification-fix.md +0 -0
  129. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-17-issue-15-i2v-bearer-auth.md +0 -0
  130. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-17-issue-15-orchestration.md +0 -0
  131. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-18-video-phase0-submit-spike.md +0 -0
  132. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-19-video-phase-a-execution-state.md +0 -0
  133. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-19-video-phase-a-orchestration.md +0 -0
  134. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-19-video-phase-a-t2v.md +0 -0
  135. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-20-video-download-t2v-cli.md +0 -0
  136. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-21-multi-image-prompt-orchestration.md +0 -0
  137. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-21-multi-image-prompt.md +0 -0
  138. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-22-pr-38-review.md +0 -0
  139. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-22-stay-mounted-batch-session-plan.md +0 -0
  140. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-23-locale-agnostic-selectors.md +0 -0
  141. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/plans/2026-05-24-data-layer.md +0 -0
  142. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-10-phase-4-hardening-design.md +0 -0
  143. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-14-shell-multi-prompt-design.md +0 -0
  144. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-15-auth-login-real-chrome-design.md +0 -0
  145. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-17-e2e-test-coverage-design.md +0 -0
  146. {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
  147. {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
  148. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-17-issue-15-root-cause-findings.md +0 -0
  149. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-18-ui-automation-video-generation-design.md +0 -0
  150. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-21-multi-image-prompt-design.md +0 -0
  151. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-22-pr-38-review-design.md +0 -0
  152. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-22-stay-mounted-batch-session-design.md +0 -0
  153. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-23-locale-agnostic-selectors.md +0 -0
  154. {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
  155. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-24-data-layer-design.md +0 -0
  156. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/specs/2026-05-27-public-event-surface-design.md +0 -0
  157. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/docs/superpowers/verifications/2026-05-11-phase-4-stage-g.md +0 -0
  158. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/examples/batch_from_config.py +0 -0
  159. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/examples/multi_prompt_t2i.py +0 -0
  160. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/examples/sample_config.json +0 -0
  161. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/examples/sample_prompts.txt +0 -0
  162. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/examples/single_image_t2i.py +0 -0
  163. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/llms.txt +0 -0
  164. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/README.md +0 -0
  165. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/01_upload_image.json +0 -0
  166. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/02_batchAsyncGenerateVideoText.json +0 -0
  167. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
  168. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/04_archive_workflow.json +0 -0
  169. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/05_createProject.json +0 -0
  170. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/06_batchGenerateImages.json +0 -0
  171. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/07_batchGenerateImages_seeded.json +0 -0
  172. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/08_batchAsyncGenerateVideoStartAndEndImage.json +0 -0
  173. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/09_batchAsyncGenerateVideoReferenceImages.json +0 -0
  174. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/10_batchCheckAsyncVideoGenerationStatus_successful.json +0 -0
  175. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/samples/captured/11_batchCheckAsyncVideoGenerationStatus_failed.json +0 -0
  176. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/ci/check_doc_links.py +0 -0
  177. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/ci/check_repo_hygiene.py +0 -0
  178. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/debug_editor.py +0 -0
  179. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/debug_gen_settings.py +0 -0
  180. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/debug_settings.py +0 -0
  181. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/dev/active_plan.py +0 -0
  182. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/dev/capture_i2v_frame_slots_dom.py +0 -0
  183. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/dev/capture_image_add_media_dom.py +0 -0
  184. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/dev/capture_locale_invariants.py +0 -0
  185. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/dev/cdp_drive_and_probe.py +0 -0
  186. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/dev/monitor_pr_38.py +0 -0
  187. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/diag_capture_flow_traffic.py +0 -0
  188. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/diag_recaptcha_mint.py +0 -0
  189. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/record_demo.ps1 +0 -0
  190. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/smoke_image.py +0 -0
  191. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/smoke_real_chrome_image.py +0 -0
  192. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/smoke_video_editor.py +0 -0
  193. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/smoke_worker_style.py +0 -0
  194. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/scripts/verify_chrome_auth_viability.py +0 -0
  195. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/skills/scenario/SKILL.md +0 -0
  196. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/sonar-project.properties +0 -0
  197. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/__main__.py +0 -0
  198. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/_cli_helpers.py +0 -0
  199. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/__init__.py +0 -0
  200. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/_retry.py +0 -0
  201. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/client.py +0 -0
  202. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/dto.py +0 -0
  203. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/image.py +0 -0
  204. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/recaptcha.py +0 -0
  205. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/routes.py +0 -0
  206. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/__init__.py +0 -0
  207. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/_common.py +0 -0
  208. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/_fingerprint.py +0 -0
  209. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/base.py +0 -0
  210. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/experimental/__init__.py +0 -0
  211. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/experimental/bearer.py +0 -0
  212. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/experimental/evaluate_fetch.py +0 -0
  213. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/api/transports/experimental/sapisidhash.py +0 -0
  214. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/auth/__init__.py +0 -0
  215. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/auth/base.py +0 -0
  216. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/auth/factory.py +0 -0
  217. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/auth/internal_chromium.py +0 -0
  218. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/auth/real_chrome.py +0 -0
  219. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/auth/strategies.py +0 -0
  220. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/auth/verification.py +0 -0
  221. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/browser_manager.py +0 -0
  222. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/cli.py +0 -0
  223. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/cli_image.py +0 -0
  224. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/cli_models.py +0 -0
  225. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/cli_run.py +0 -0
  226. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/config.py +0 -0
  227. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/__init__.py +0 -0
  228. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/migrations/0001_initial.sql +0 -0
  229. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/migrations/0002_add_cloud_storage.sql +0 -0
  230. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/migrations/__init__.py +0 -0
  231. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/models.py +0 -0
  232. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/queries.py +0 -0
  233. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/redaction.py +0 -0
  234. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/repository.py +0 -0
  235. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/data/store.py +0 -0
  236. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/exceptions.py +0 -0
  237. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/image_batch.py +0 -0
  238. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/json_output.py +0 -0
  239. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/manifest.py +0 -0
  240. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/observability.py +0 -0
  241. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/paths.py +0 -0
  242. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/profile_store.py +0 -0
  243. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/src/gflow_cli/storage.py +0 -0
  244. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tasks/lessons.md +0 -0
  245. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/test_assets/sample_batch.json +0 -0
  246. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/test_assets/sample_batch.tsv +0 -0
  247. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/test_assets/sample_batch_invalid.tsv +0 -0
  248. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/__init__.py +0 -0
  249. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/__init__.py +0 -0
  250. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_client.py +0 -0
  251. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_client_image.py +0 -0
  252. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_concurrency.py +0 -0
  253. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_dto.py +0 -0
  254. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_image.py +0 -0
  255. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_image_dto.py +0 -0
  256. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_recaptcha.py +0 -0
  257. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_retry.py +0 -0
  258. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/test_routes.py +0 -0
  259. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/__init__.py +0 -0
  260. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_base.py +0 -0
  261. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_bearer.py +0 -0
  262. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_common.py +0 -0
  263. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_evaluate_fetch.py +0 -0
  264. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_factory.py +0 -0
  265. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_fingerprint.py +0 -0
  266. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_sapisidhash.py +0 -0
  267. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_transport_timeout.py +0 -0
  268. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_ui_automation_batch.py +0 -0
  269. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/api/transports/test_ui_automation_image_mode.py +0 -0
  270. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/auth/strategies/test_factory.py +0 -0
  271. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/auth/strategies/test_strategies.py +0 -0
  272. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/auth/test_verification.py +0 -0
  273. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/__init__.py +0 -0
  274. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_cli_auth_list.py +0 -0
  275. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_cli_data.py +0 -0
  276. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_cli_image.py +0 -0
  277. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_cli_image_seed_removed.py +0 -0
  278. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_cli_models.py +0 -0
  279. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_cli_run.py +0 -0
  280. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_error_handling.py +0 -0
  281. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_helpers.py +0 -0
  282. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/cli/test_t2i_multi_prompt.py +0 -0
  283. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/conftest.py +0 -0
  284. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/data/__init__.py +0 -0
  285. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/data/test_packaging.py +0 -0
  286. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/data/test_recorder.py +0 -0
  287. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/data/test_redaction.py +0 -0
  288. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/data/test_repository.py +0 -0
  289. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/data/test_settings_and_errors.py +0 -0
  290. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/data/test_store_migrations.py +0 -0
  291. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/__init__.py +0 -0
  292. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/conftest.py +0 -0
  293. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_auth_verification_e2e.py +0 -0
  294. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_data_layer_e2e.py +0 -0
  295. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_image_batch_e2e.py +0 -0
  296. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_image_i2i_ref_cap_e2e.py +0 -0
  297. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_json_output_e2e.py +0 -0
  298. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_locale_selectors_e2e.py +0 -0
  299. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_video_r2v_ref_cap_e2e.py +0 -0
  300. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/e2e/test_video_t2v_e2e.py +0 -0
  301. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/__init__.py +0 -0
  302. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/auth.feature +0 -0
  303. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/auth_login.feature +0 -0
  304. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/conftest.py +0 -0
  305. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/image.feature +0 -0
  306. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/test_auth_login_steps.py +0 -0
  307. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/test_auth_steps.py +0 -0
  308. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/test_image_steps.py +0 -0
  309. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/features/test_step_collision_guard.py +0 -0
  310. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/fixtures/__init__.py +0 -0
  311. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/fixtures/seeded_catalog.py +0 -0
  312. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/image_batch/__init__.py +0 -0
  313. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/image_batch/test_image_manifest.py +0 -0
  314. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/image_batch/test_observability_events.py +0 -0
  315. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/integration/__init__.py +0 -0
  316. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/integration/conftest.py +0 -0
  317. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/integration/constants.py +0 -0
  318. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/integration/test_storage_gcs.py +0 -0
  319. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/integration/test_storage_s3.py +0 -0
  320. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/scripts/test_capture_locale_invariants.py +0 -0
  321. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/smoke/__init__.py +0 -0
  322. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/smoke/test_profile_account_smoke.py +0 -0
  323. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/smoke/test_real_flow.py +0 -0
  324. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_auth.py +0 -0
  325. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_browser_manager.py +0 -0
  326. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_cli_data.py +0 -0
  327. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_config.py +0 -0
  328. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_conftest_isolation.py +0 -0
  329. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_data_queries.py +0 -0
  330. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_documentation_gate.py +0 -0
  331. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_json_output.py +0 -0
  332. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_manifest.py +0 -0
  333. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_marker_registry.py +0 -0
  334. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_observability.py +0 -0
  335. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_paths.py +0 -0
  336. {gflow_cli-0.10.0 → gflow_cli-0.11.0}/tests/test_profile_store.py +0 -0
  337. {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.10.0...HEAD
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 still partially localized — issue #24 partial
318
+ ### `UiAutomationTransport` selectors locale-agnostic — issue #24 Phase 5 complete
319
319
 
320
- - **Status:** Mitigated · **Severity:** Medium · **Tracking:** [issue #24](https://github.com/ffroliva/gflow-cli/issues/24)
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
- Status stays *Mitigated* (not *Resolved*) because `--lang=en-US` is still
323
- passed and `NEW_PROJECT_SELECTORS` / `SUBMIT_BUTTON_SELECTORS` tails still
324
- carry English-text fallbacks; the icon-first leads cover the common path,
325
- but the dependency only fully clears after a live e2e on a non-English
326
- Chrome profile.
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
- **Full resolution requires:** live e2e verification on a non-English Chrome profile
406
- (`GFLOW_CLI_LOCALE=<non-EN>` + a non-English browser profile) to confirm no
407
- regression, then removing `--lang=en-US`.
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