gflow-cli 0.18.0__tar.gz → 0.20.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 (432) hide show
  1. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.env.template +9 -0
  2. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/CHANGELOG.md +34 -1
  3. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/PKG-INFO +3 -1
  4. gflow_cli-0.20.0/docs/AGENT_UI_E2E.md +108 -0
  5. gflow_cli-0.20.0/docs/AGENT_UI_RECON.md +192 -0
  6. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/CONFIGURATION.md +10 -0
  7. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/INDEX.md +2 -1
  8. gflow_cli-0.20.0/docs/LIVE_VERIFICATION_v0.19.0.md +60 -0
  9. gflow_cli-0.20.0/docs/LIVE_VERIFICATION_v0.20.0.md +76 -0
  10. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/SECURITY.md +20 -0
  11. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/USAGE.md +1 -0
  12. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/pyproject.toml +10 -1
  13. gflow_cli-0.20.0/scripts/dev/analyze_agent_ui_capture.py +146 -0
  14. gflow_cli-0.20.0/scripts/dev/spike_patchright.py +357 -0
  15. gflow_cli-0.20.0/scripts/e2e/agentic_image_e2e.ps1 +74 -0
  16. gflow_cli-0.20.0/scripts/e2e/capture_agent_toggle.py +101 -0
  17. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/__init__.py +1 -1
  18. gflow_cli-0.20.0/src/gflow_cli/api/_engine.py +113 -0
  19. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/_retry.py +5 -3
  20. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/client.py +22 -3
  21. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/recaptcha.py +11 -3
  22. gflow_cli-0.20.0/src/gflow_cli/api/transports/drivers/__init__.py +32 -0
  23. gflow_cli-0.20.0/src/gflow_cli/api/transports/drivers/agentic.py +465 -0
  24. gflow_cli-0.20.0/src/gflow_cli/api/transports/drivers/base.py +102 -0
  25. gflow_cli-0.20.0/src/gflow_cli/api/transports/drivers/classic.py +224 -0
  26. gflow_cli-0.20.0/src/gflow_cli/api/transports/drivers/factory.py +135 -0
  27. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/transports/ui_automation.py +156 -21
  28. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/transports/ui_automation_video.py +49 -22
  29. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/cli.py +21 -1
  30. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/config.py +25 -0
  31. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/errors.py +46 -0
  32. gflow_cli-0.20.0/tests/api/test_engine.py +95 -0
  33. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_retry.py +27 -0
  34. gflow_cli-0.20.0/tests/api/transports/conftest.py +22 -0
  35. gflow_cli-0.20.0/tests/api/transports/drivers/test_agentic.py +500 -0
  36. gflow_cli-0.20.0/tests/api/transports/drivers/test_factory.py +143 -0
  37. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/transports/test_ui_automation.py +25 -5
  38. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/transports/test_ui_automation_batch.py +29 -20
  39. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/transports/test_ui_automation_image_mode.py +55 -16
  40. gflow_cli-0.20.0/tests/cli/test_settings_validation.py +35 -0
  41. gflow_cli-0.20.0/tests/features/test_video_agent_ui_steps.py +447 -0
  42. gflow_cli-0.20.0/tests/features/video_agent_ui.feature +34 -0
  43. gflow_cli-0.20.0/tests/scripts/test_analyze_agent_ui_capture.py +113 -0
  44. gflow_cli-0.20.0/tests/smoke/__init__.py +0 -0
  45. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_config.py +27 -1
  46. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_errors.py +46 -0
  47. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/uv.lock +25 -2
  48. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.claude/README.md +0 -0
  49. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.claude/commands/gflow/active.md +0 -0
  50. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.claude/commands/gflow/branch-review.md +0 -0
  51. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.claude/commands/gflow/changelog.md +0 -0
  52. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.claude/commands/gflow/check.md +0 -0
  53. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.claude/commands/gflow/doc-review.md +0 -0
  54. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.claude/commands/gflow/known-issues.md +0 -0
  55. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.claude/commands/gflow/next.md +0 -0
  56. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.claude/commands/gflow/plan.md +0 -0
  57. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.claude/commands/gflow/pr-council-review.md +0 -0
  58. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.claude/commands/gflow/predict.md +0 -0
  59. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.claude/commands/gflow/release.md +0 -0
  60. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.claude/commands/gflow/scenario.md +0 -0
  61. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.claude/commands/gflow/status.md +0 -0
  62. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.gitattributes +0 -0
  63. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.github/CODEOWNERS +0 -0
  64. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  65. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.github/copilot-instructions.md +0 -0
  66. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.github/dependabot.yml +0 -0
  67. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.github/workflows/ci.yml +0 -0
  68. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.github/workflows/external-pr-triage.yml +0 -0
  69. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.github/workflows/governance-advisory.yml +0 -0
  70. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.github/workflows/governance-benchmark.yml +0 -0
  71. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.github/workflows/release.yml +0 -0
  72. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.gitignore +0 -0
  73. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.gitleaks.toml +0 -0
  74. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.pre-commit-config.yaml +0 -0
  75. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/.secrets.baseline +0 -0
  76. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/AGENTS.md +0 -0
  77. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/CLAUDE.md +0 -0
  78. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/CONFIGURATION.md +0 -0
  79. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/CONTRIBUTING.md +0 -0
  80. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/DISCLAIMER.md +0 -0
  81. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/GEMINI.md +0 -0
  82. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/KNOWN_ISSUES.md +0 -0
  83. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/LICENSE +0 -0
  84. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/PLAN.md +0 -0
  85. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/README.md +0 -0
  86. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/RELEASE.md +0 -0
  87. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/ROADMAP.md +0 -0
  88. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/conftest.py +0 -0
  89. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docker-compose.yml +0 -0
  90. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/AGENT_GUIDE.md +0 -0
  91. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/ARCHITECTURE.md +0 -0
  92. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/AUTHENTICATION.md +0 -0
  93. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/CHARACTER.md +0 -0
  94. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/CHARACTER_RECON.md +0 -0
  95. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/DATA_LAYER.md +0 -0
  96. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/DEBUGGING.md +0 -0
  97. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/DEMOS.md +0 -0
  98. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/DEVELOPMENT.md +0 -0
  99. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/E2E_TESTING.md +0 -0
  100. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/EXTERNAL_STORAGE.md +0 -0
  101. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/GITHUB.md +0 -0
  102. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/GOVERNANCE_BENCHMARK.md +0 -0
  103. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/IMAGE_UPSCALE_RECON.md +0 -0
  104. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/LIVE_VERIFICATION_data_layer.md +0 -0
  105. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/LIVE_VERIFICATION_image_batch.md +0 -0
  106. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/LIVE_VERIFICATION_v0.10.0.md +0 -0
  107. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/LIVE_VERIFICATION_v0.11.0.md +0 -0
  108. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/LIVE_VERIFICATION_v0.12.0.md +0 -0
  109. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/LIVE_VERIFICATION_v0.13.0.md +0 -0
  110. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/LIVE_VERIFICATION_v0.16.0.md +0 -0
  111. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/LIVE_VERIFICATION_v0.17.0.md +0 -0
  112. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/LIVE_VERIFICATION_v0.18.0.md +0 -0
  113. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/LIVE_VERIFICATION_v0.7.0.md +0 -0
  114. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/LIVE_VERIFICATION_v0.8.1.md +0 -0
  115. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/LIVE_VERIFICATION_v0.9.0.md +0 -0
  116. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/LIVE_VERIFICATION_v0.9.1.md +0 -0
  117. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/LIVE_VERIFICATION_video_download.md +0 -0
  118. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/MOVIE.md +0 -0
  119. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/PROJECT_STATUS.md +0 -0
  120. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/USER_GUIDE.md +0 -0
  121. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/assets/demo-split-pf.gif +0 -0
  122. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/assets/example-run.gif +0 -0
  123. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/schemas/movie-handoff.schema.json +0 -0
  124. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/docs/superpowers/plans/2026-06-12-issue-174-library-ui-attach/PLAN.md +0 -0
  125. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/examples/README.md +0 -0
  126. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/examples/batch_from_config.py +0 -0
  127. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/examples/multi_prompt_t2i.py +0 -0
  128. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/examples/sample_config.json +0 -0
  129. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/examples/sample_prompts.txt +0 -0
  130. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/examples/single_image_t2i.py +0 -0
  131. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/examples/workflow_chain.py +0 -0
  132. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/llms.txt +0 -0
  133. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/samples/README.md +0 -0
  134. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/samples/captured/01_upload_image.json +0 -0
  135. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/samples/captured/02_batchAsyncGenerateVideoText.json +0 -0
  136. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
  137. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/samples/captured/04_archive_workflow.json +0 -0
  138. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/samples/captured/05_createProject.json +0 -0
  139. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/samples/captured/06_batchGenerateImages.json +0 -0
  140. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/samples/captured/07_batchGenerateImages_seeded.json +0 -0
  141. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/samples/captured/08_batchAsyncGenerateVideoStartAndEndImage.json +0 -0
  142. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/samples/captured/09_batchAsyncGenerateVideoReferenceImages.json +0 -0
  143. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/samples/captured/10_batchCheckAsyncVideoGenerationStatus_successful.json +0 -0
  144. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/samples/captured/11_batchCheckAsyncVideoGenerationStatus_failed.json +0 -0
  145. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/samples/captured/12_create_scene.json +0 -0
  146. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/samples/captured/13_sceneWorkflows_update.json +0 -0
  147. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/samples/captured/14_get_scene_workflows.json +0 -0
  148. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/samples/captured/15_commit_flowWorkflow.json +0 -0
  149. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/ci/check_doc_links.py +0 -0
  150. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/ci/check_materiality.py +0 -0
  151. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/ci/check_repo_hygiene.py +0 -0
  152. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/debug_editor.py +0 -0
  153. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/debug_gen_settings.py +0 -0
  154. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/debug_settings.py +0 -0
  155. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/_recording_client.py +0 -0
  156. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/_spike_common.py +0 -0
  157. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/active_plan.py +0 -0
  158. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/capture_i2v_frame_slots_dom.py +0 -0
  159. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/capture_i2v_intercept_submit.py +0 -0
  160. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/capture_i2v_model_select_repro.py +0 -0
  161. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/capture_i2v_post_bind_state.py +0 -0
  162. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/capture_image_add_media_dom.py +0 -0
  163. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/capture_locale_invariants.py +0 -0
  164. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/cdp_drive_and_probe.py +0 -0
  165. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/character_create_spike.py +0 -0
  166. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/character_create_spike_v2.py +0 -0
  167. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/dump_character_selectors.js +0 -0
  168. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/make_project.py +0 -0
  169. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/materiality_backtest.py +0 -0
  170. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/monitor_pr_38.py +0 -0
  171. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/patch_character.py +0 -0
  172. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/record_flow_capture.py +0 -0
  173. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/skillopt/README.md +0 -0
  174. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/skillopt/harness.py +0 -0
  175. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/skillopt/tasks.json +0 -0
  176. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/spike_char_editor_dom.py +0 -0
  177. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/spike_char_gen_capture.py +0 -0
  178. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/spike_image_upscale_capture.py +0 -0
  179. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/spike_image_upscale_drive.py +0 -0
  180. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/spike_image_upscale_recaptcha_action.py +0 -0
  181. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/spike_image_upscale_rest_probe.py +0 -0
  182. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/spike_issue170_picker_locale_recon.py +0 -0
  183. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/spike_issue174_library_ui_recon.py +0 -0
  184. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/spike_movie_attach_payload.py +0 -0
  185. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/spike_movie_entity_recon.py +0 -0
  186. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/spike_movie_gen_capture.py +0 -0
  187. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/spike_movie_picker_select.py +0 -0
  188. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/spike_movie_voice_list.py +0 -0
  189. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/dev/spike_patch_entity.py +0 -0
  190. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/diag/README.md +0 -0
  191. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/diag/capture_flow_traffic.py +0 -0
  192. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/diag/memory_profile.py +0 -0
  193. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/diag/recaptcha_mint.py +0 -0
  194. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/record_demo.ps1 +0 -0
  195. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/smoke_image.py +0 -0
  196. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/smoke_real_chrome_image.py +0 -0
  197. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/smoke_video_editor.py +0 -0
  198. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/smoke_worker_style.py +0 -0
  199. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/scripts/verify_chrome_auth_viability.py +0 -0
  200. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/skills/README.md +0 -0
  201. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/skills/gflow-cli/SKILL.md +0 -0
  202. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/skills/plan/SKILL.md +0 -0
  203. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/skills/pr-council-review/SKILL.md +0 -0
  204. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/skills/predict/SKILL.md +0 -0
  205. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/skills/scenario/SKILL.md +0 -0
  206. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/skills/status/SKILL.md +0 -0
  207. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/sonar-project.properties +0 -0
  208. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/__main__.py +0 -0
  209. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/_cli_helpers.py +0 -0
  210. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/__init__.py +0 -0
  211. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/_sapisidhash.py +0 -0
  212. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/character.py +0 -0
  213. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/dto.py +0 -0
  214. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/image.py +0 -0
  215. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/image_upscale.py +0 -0
  216. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/routes.py +0 -0
  217. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/scene.py +0 -0
  218. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/transports/__init__.py +0 -0
  219. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/transports/_common.py +0 -0
  220. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/transports/_fingerprint.py +0 -0
  221. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/transports/base.py +0 -0
  222. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/transports/experimental/__init__.py +0 -0
  223. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/transports/experimental/bearer.py +0 -0
  224. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/transports/experimental/evaluate_fetch.py +0 -0
  225. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/transports/experimental/sapisidhash.py +0 -0
  226. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/api/video.py +0 -0
  227. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/auth/__init__.py +0 -0
  228. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/auth/base.py +0 -0
  229. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/auth/cookies.py +0 -0
  230. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/auth/factory.py +0 -0
  231. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/auth/internal_chromium.py +0 -0
  232. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/auth/real_chrome.py +0 -0
  233. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/auth/strategies.py +0 -0
  234. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/auth/verification.py +0 -0
  235. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/browser_manager.py +0 -0
  236. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/chain.py +0 -0
  237. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/chain_manifest.py +0 -0
  238. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/cli_character.py +0 -0
  239. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/cli_data.py +0 -0
  240. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/cli_image.py +0 -0
  241. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/cli_models.py +0 -0
  242. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/cli_movie.py +0 -0
  243. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/cli_run.py +0 -0
  244. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/cli_scene.py +0 -0
  245. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/cli_video.py +0 -0
  246. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/composition.py +0 -0
  247. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/data/__init__.py +0 -0
  248. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/data/chain_repo.py +0 -0
  249. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/data/migrations/0001_initial.sql +0 -0
  250. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/data/migrations/0002_add_cloud_storage.sql +0 -0
  251. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/data/migrations/0003_add_scene_tables.sql +0 -0
  252. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/data/migrations/0004_add_scene_output_path.sql +0 -0
  253. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/data/migrations/0005_add_chain_links.sql +0 -0
  254. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/data/migrations/0006_add_operations_metadata.sql +0 -0
  255. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/data/migrations/__init__.py +0 -0
  256. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/data/models.py +0 -0
  257. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/data/queries.py +0 -0
  258. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/data/recorder.py +0 -0
  259. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/data/redaction.py +0 -0
  260. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/data/repository.py +0 -0
  261. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/data/store.py +0 -0
  262. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/exceptions.py +0 -0
  263. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/image_batch.py +0 -0
  264. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/json_output.py +0 -0
  265. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/manifest.py +0 -0
  266. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/media.py +0 -0
  267. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/movie_manifest.py +0 -0
  268. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/observability.py +0 -0
  269. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/paths.py +0 -0
  270. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/profile_store.py +0 -0
  271. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/services/__init__.py +0 -0
  272. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/services/character_create.py +0 -0
  273. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/src/gflow_cli/storage.py +0 -0
  274. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tasks/lessons.md +0 -0
  275. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/test_assets/sample_batch.json +0 -0
  276. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/test_assets/sample_batch.tsv +0 -0
  277. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/test_assets/sample_batch_invalid.tsv +0 -0
  278. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/__init__.py +0 -0
  279. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/__init__.py +0 -0
  280. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/fixtures/character_gen_response.json +0 -0
  281. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/fixtures/patch_entity_response.json +0 -0
  282. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_aisandbox_auth_error.py +0 -0
  283. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_aisandbox_auth_headers.py +0 -0
  284. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_bearer_redaction.py +0 -0
  285. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_character.py +0 -0
  286. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_client.py +0 -0
  287. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_client_character.py +0 -0
  288. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_client_delete_characters.py +0 -0
  289. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_client_generate_character.py +0 -0
  290. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_client_image.py +0 -0
  291. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_client_launch_kwargs.py +0 -0
  292. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_client_patch_entity.py +0 -0
  293. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_client_scene.py +0 -0
  294. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_client_upscale.py +0 -0
  295. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_concurrency.py +0 -0
  296. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_dto.py +0 -0
  297. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_image.py +0 -0
  298. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_image_dto.py +0 -0
  299. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_image_upscale.py +0 -0
  300. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_post_json_aisandbox_auth.py +0 -0
  301. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_recaptcha.py +0 -0
  302. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_routes.py +0 -0
  303. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_routes_character.py +0 -0
  304. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_routes_scene.py +0 -0
  305. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_sapisidhash_helper.py +0 -0
  306. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_scene_models.py +0 -0
  307. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_video.py +0 -0
  308. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/test_video_request.py +0 -0
  309. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/transports/__init__.py +0 -0
  310. {gflow_cli-0.18.0/tests/cli → gflow_cli-0.20.0/tests/api/transports/drivers}/__init__.py +0 -0
  311. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/transports/test_base.py +0 -0
  312. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/transports/test_bearer.py +0 -0
  313. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/transports/test_common.py +0 -0
  314. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/transports/test_evaluate_fetch.py +0 -0
  315. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/transports/test_factory.py +0 -0
  316. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/transports/test_fingerprint.py +0 -0
  317. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/transports/test_sapisidhash.py +0 -0
  318. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/transports/test_transport_timeout.py +0 -0
  319. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/transports/test_ui_automation_video.py +0 -0
  320. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/api/transports/test_ui_character_editor.py +0 -0
  321. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/auth/strategies/test_factory.py +0 -0
  322. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/auth/strategies/test_strategies.py +0 -0
  323. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/auth/test_verification.py +0 -0
  324. {gflow_cli-0.18.0/tests/data → gflow_cli-0.20.0/tests/cli}/__init__.py +0 -0
  325. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_cli_auth_list.py +0 -0
  326. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_cli_character.py +0 -0
  327. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_cli_character_create.py +0 -0
  328. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_cli_data.py +0 -0
  329. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_cli_image.py +0 -0
  330. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_cli_image_seed_removed.py +0 -0
  331. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_cli_image_selector_drift.py +0 -0
  332. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_cli_image_upscale.py +0 -0
  333. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_cli_models.py +0 -0
  334. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_cli_movie.py +0 -0
  335. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_cli_run.py +0 -0
  336. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_cli_scene.py +0 -0
  337. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_cli_video.py +0 -0
  338. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_cli_video_chain.py +0 -0
  339. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_error_handling.py +0 -0
  340. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_helpers.py +0 -0
  341. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_movie_manifest.py +0 -0
  342. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/cli/test_t2i_multi_prompt.py +0 -0
  343. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/composition/test_character.py +0 -0
  344. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/composition/test_compose_prompt.py +0 -0
  345. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/composition/test_handoff.py +0 -0
  346. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/conftest.py +0 -0
  347. {gflow_cli-0.18.0/tests/e2e → gflow_cli-0.20.0/tests/data}/__init__.py +0 -0
  348. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/data/test_chain_repo.py +0 -0
  349. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/data/test_find_incomplete_character.py +0 -0
  350. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/data/test_models.py +0 -0
  351. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/data/test_packaging.py +0 -0
  352. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/data/test_recorder.py +0 -0
  353. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/data/test_recorder_character.py +0 -0
  354. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/data/test_redaction.py +0 -0
  355. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/data/test_repository.py +0 -0
  356. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/data/test_scene_persistence.py +0 -0
  357. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/data/test_settings_and_errors.py +0 -0
  358. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/data/test_store_migrations.py +0 -0
  359. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/dev/test_record_flow_capture.py +0 -0
  360. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/dev/test_recording_client.py +0 -0
  361. {gflow_cli-0.18.0/tests/features → gflow_cli-0.20.0/tests/e2e}/__init__.py +0 -0
  362. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/e2e/conftest.py +0 -0
  363. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/e2e/test_aisandbox_auth_live.py +0 -0
  364. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/e2e/test_auth_verification_e2e.py +0 -0
  365. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/e2e/test_chain_e2e.py +0 -0
  366. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/e2e/test_character_create_e2e.py +0 -0
  367. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/e2e/test_data_layer_e2e.py +0 -0
  368. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/e2e/test_i2v_flags_e2e.py +0 -0
  369. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/e2e/test_image_batch_e2e.py +0 -0
  370. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/e2e/test_image_i2i_ref_cap_e2e.py +0 -0
  371. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/e2e/test_json_output_e2e.py +0 -0
  372. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/e2e/test_locale_selectors_e2e.py +0 -0
  373. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/e2e/test_scene_compose_live.py +0 -0
  374. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/e2e/test_transports_e2e.py +0 -0
  375. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/e2e/test_video_r2v_ref_cap_e2e.py +0 -0
  376. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/e2e/test_video_t2v_e2e.py +0 -0
  377. {gflow_cli-0.18.0/tests/fixtures → gflow_cli-0.20.0/tests/features}/__init__.py +0 -0
  378. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/auth.feature +0 -0
  379. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/auth_login.feature +0 -0
  380. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/character_create.feature +0 -0
  381. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/character_read.feature +0 -0
  382. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/conftest.py +0 -0
  383. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/image.feature +0 -0
  384. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/image_upscale.feature +0 -0
  385. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/locale_picker_include.feature +0 -0
  386. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/test_auth_login_steps.py +0 -0
  387. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/test_auth_steps.py +0 -0
  388. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/test_character_create_steps.py +0 -0
  389. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/test_character_read_steps.py +0 -0
  390. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/test_image_steps.py +0 -0
  391. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/test_image_upscale_steps.py +0 -0
  392. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/test_locale_picker_include_steps.py +0 -0
  393. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/test_step_collision_guard.py +0 -0
  394. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/test_video_chain_steps.py +0 -0
  395. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/features/video_chain.feature +0 -0
  396. {gflow_cli-0.18.0/tests/image_batch → gflow_cli-0.20.0/tests/fixtures}/__init__.py +0 -0
  397. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/fixtures/seeded_catalog.py +0 -0
  398. {gflow_cli-0.18.0/tests/integration → gflow_cli-0.20.0/tests/image_batch}/__init__.py +0 -0
  399. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/image_batch/test_image_manifest.py +0 -0
  400. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/image_batch/test_observability_events.py +0 -0
  401. {gflow_cli-0.18.0/tests/services → gflow_cli-0.20.0/tests/integration}/__init__.py +0 -0
  402. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/integration/conftest.py +0 -0
  403. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/integration/constants.py +0 -0
  404. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/integration/test_storage_gcs.py +0 -0
  405. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/integration/test_storage_s3.py +0 -0
  406. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/scripts/test_capture_locale_invariants.py +0 -0
  407. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/scripts/test_check_materiality.py +0 -0
  408. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/scripts/test_check_repo_hygiene.py +0 -0
  409. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/scripts/test_materiality_backtest.py +0 -0
  410. {gflow_cli-0.18.0/tests/smoke → gflow_cli-0.20.0/tests/services}/__init__.py +0 -0
  411. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/services/test_character_create_redaction.py +0 -0
  412. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/services/test_character_create_saga.py +0 -0
  413. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/services/test_character_gen_no_direct_post.py +0 -0
  414. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/smoke/test_profile_account_smoke.py +0 -0
  415. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/smoke/test_real_flow.py +0 -0
  416. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_auth.py +0 -0
  417. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_browser_manager.py +0 -0
  418. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_chain.py +0 -0
  419. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_chain_manifest.py +0 -0
  420. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_cli_data.py +0 -0
  421. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_conftest_isolation.py +0 -0
  422. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_data_queries.py +0 -0
  423. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_documentation_gate.py +0 -0
  424. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_errors_403.py +0 -0
  425. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_json_output.py +0 -0
  426. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_manifest.py +0 -0
  427. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_marker_registry.py +0 -0
  428. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_media.py +0 -0
  429. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_observability.py +0 -0
  430. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_paths.py +0 -0
  431. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_profile_store.py +0 -0
  432. {gflow_cli-0.18.0 → gflow_cli-0.20.0}/tests/test_smoke.py +0 -0
@@ -106,6 +106,15 @@
106
106
  # visible window). The session is still reused from the persistent profile.
107
107
  # GFLOW_CLI_HEADLESS=true
108
108
 
109
+ # Browser automation engine — playwright (default) | patchright
110
+ # patchright is an OPT-IN, drop-in patched Playwright (Chromium) that avoids the
111
+ # Runtime.enable CDP leak for stronger reCAPTCHA-Enterprise evasion on the HEADED
112
+ # path. It is NOT a headless unlock. Requires a separate install:
113
+ # pip install patchright (or: pip install 'gflow-cli[patchright]')
114
+ # When using system Chrome (channel=chrome, the gflow default) you do NOT need
115
+ # `patchright install chromium`. Unset to revert to the default playwright engine.
116
+ # GFLOW_CLI_BROWSER_ENGINE=playwright
117
+
109
118
  # BCP-47 locale tag passed to Playwright's launch `locale=` parameter
110
119
  # (controls Accept-Language only — Chrome's UI language is forced to
111
120
  # en-US via the `--lang=en-US` launch arg regardless of this setting, so
@@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.20.0] — 2026-06-15
11
+
12
+ ### Added
13
+
14
+ - **Forced Agentic UI detection** (exit code 25): dynamically detects if the account's Flow editor page has been placed in Google Flow's new Agentic UI A/B cohort. Raises `FlowAgentUiError` and captures a diagnostic viewport screenshot (`debug_forced_agent_ui.png`) to exit cleanly and prevent CLI hangs.
15
+ - **Pluggable Flow UI driver strategy** (`FlowUiDriver`): the UI-automation transport now probes the editor DOM **per generation** (the cohort flaps per page load) and binds a `ClassicFlowUiDriver` or `AgenticFlowUiDriver`, so the two cohorts' selectors never share code. Classic generation is unchanged.
16
+ - **Agentic-cohort image generation** (validated live): when the editor is served the Agentic UI, `gflow image` drives it by encoding settings (count / aspect) into the conversational prompt directive and scraping generated assets directly from the DOM — **deduplicated by media UUID** — because the Agentic UI routes generation through a background Web Worker that defeats page-level network capture. Content-policy blocks (detected in alert/dialog regions) fail fast with `ContentPolicyError` (exit 5). Agentic **video** still raises `FlowAgentUiError` (exit 25) pending a validated scraping path.
17
+ - **`GFLOW_CLI_FORCE_AGENT_UI`** (testing/diagnostic opt-in): forces the agentic composer by clicking the in-input "Agent" toggle after entering the editor, so the agentic path can be exercised deterministically regardless of the server-assigned A/B cohort (which has no client-readable flag). Unset by default — the cohort is auto-detected per generation. See `docs/AGENT_UI_E2E.md`.
18
+
19
+ ## [0.19.0] — 2026-06-12
20
+
21
+ ### Added
22
+
23
+ - **Opt-in Patchright browser engine** via `GFLOW_CLI_BROWSER_ENGINE=patchright`
24
+ (default `playwright`, unchanged). Patchright is a drop-in patched Playwright
25
+ (Chromium) that runs page evaluations in an isolated execution context to
26
+ avoid the `Runtime.enable` CDP leak, for stronger reCAPTCHA-Enterprise evasion
27
+ on the **headed** path. It is **not** a headless unlock and must be installed
28
+ separately: `pip install 'gflow-cli[patchright]'`. The default engine is
29
+ byte-identical to before. `gflow auth status` now reports the active engine.
30
+ - `BrowserEngineUnavailableError` (exit code 24): selecting `patchright` without
31
+ the package installed now fails with a clear `pip install patchright`
32
+ remediation hint instead of a raw `ImportError` hashed to a generic exit 1.
33
+
34
+ ### Fixed
35
+
36
+ - An invalid `GFLOW_CLI_*` enum value (e.g. a typo'd `GFLOW_CLI_BROWSER_ENGINE`,
37
+ `GFLOW_CLI_PROVIDER`, or `GFLOW_CLI_LOG_LEVEL`) now fails with a clean
38
+ configuration error and **exit code 11** naming the offending variable, instead
39
+ of leaking a raw pydantic `ValidationError` traceback and exiting 1.
40
+
10
41
  ## [0.18.0] — 2026-06-12
11
42
 
12
43
  ### Added
@@ -1527,7 +1558,9 @@ shell-script template that branches on these codes.
1527
1558
 
1528
1559
  First skeleton. Not functional end-to-end yet.
1529
1560
 
1530
- [Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.18.0...HEAD
1561
+ [Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.20.0...HEAD
1562
+ [0.20.0]: https://github.com/ffroliva/gflow-cli/compare/v0.19.0...v0.20.0
1563
+ [0.19.0]: https://github.com/ffroliva/gflow-cli/compare/v0.18.0...v0.19.0
1531
1564
  [0.18.0]: https://github.com/ffroliva/gflow-cli/compare/v0.17.0...v0.18.0
1532
1565
  [0.17.0]: https://github.com/ffroliva/gflow-cli/compare/v0.16.0...v0.17.0
1533
1566
  [0.16.0]: https://github.com/ffroliva/gflow-cli/compare/v0.15.1...v0.16.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gflow-cli
3
- Version: 0.18.0
3
+ Version: 0.20.0
4
4
  Summary: Unofficial CLI for Google Flow — drive Veo image-to-video generations from the terminal.
5
5
  Project-URL: Homepage, https://github.com/ffroliva/gflow-cli
6
6
  Project-URL: Issues, https://github.com/ffroliva/gflow-cli/issues
@@ -58,6 +58,8 @@ Requires-Dist: ruff>=0.15.16; extra == 'dev'
58
58
  Provides-Extra: gcs
59
59
  Requires-Dist: gcsfs>=2024.2.0; extra == 'gcs'
60
60
  Requires-Dist: universal-pathlib>=0.2.5; extra == 'gcs'
61
+ Provides-Extra: patchright
62
+ Requires-Dist: patchright==1.60.1; extra == 'patchright'
61
63
  Provides-Extra: s3
62
64
  Requires-Dist: s3fs>=2024.2.0; extra == 's3'
63
65
  Requires-Dist: universal-pathlib>=0.2.5; extra == 's3'
@@ -0,0 +1,108 @@
1
+ # Agentic UI — End-to-End Testing Runbook
2
+
3
+ > How to **deterministically** drive and validate `gflow`'s **Agentic UI** image
4
+ > path against live Google Flow. Companion to
5
+ > [AGENT_UI_RECON.md](AGENT_UI_RECON.md) (the reverse-engineered wire/DOM spec)
6
+ > and [LIVE_VERIFICATION_v0.20.0.md](LIVE_VERIFICATION_v0.20.0.md) (the shipped
7
+ > evidence).
8
+
9
+ ## The problem, and the way in
10
+
11
+ Google Flow serves the composer via a **server-assigned A/B cohort** that flaps
12
+ per page load and has **no client-readable flag** — so the agentic UI cannot be
13
+ *requested*. A naive "retry until the dice land agentic" e2e is unreliable (we
14
+ observed 7 classic loads in a row).
15
+
16
+ **The deterministic trigger:** the *classic* composer exposes an in-input
17
+ **"Agent" toggle**. Clicking it switches the composer into the **same** agentic
18
+ layout — confirmed live (`scripts/e2e/capture_agent_toggle.py`, 2026-06-14):
19
+
20
+ | Signal | Before toggle | After toggle |
21
+ |---|---|---|
22
+ | `crop_*` media trigger | present | **gone** |
23
+ | `tune` settings gear | absent | **present** |
24
+ | Slate composer | present | present |
25
+
26
+ So `tune` appears and `crop_*` disappears → `detect_ui_mode` then binds the
27
+ agentic driver. An **`expand_content`** button opens the full agent side panel.
28
+
29
+ ## Repeatable procedure (deterministic)
30
+
31
+ Set **`GFLOW_CLI_FORCE_AGENT_UI=1`** and the transport clicks the Agent toggle
32
+ after entering the editor, forcing the agentic path on any load. The harness
33
+ runs that and verifies the whole chain:
34
+
35
+ ```powershell
36
+ # From repo root. Image generation is free — safe to run repeatedly.
37
+ .\scripts\e2e\agentic_image_e2e.ps1 -Profile denon82 -Count 1
38
+ .\scripts\e2e\agentic_image_e2e.ps1 -Profile denon82 -Count 3 # also exercises dedup
39
+ ```
40
+
41
+ It PASSes only when all four hold (else it prints which stage failed):
42
+
43
+ 1. `agent_mode_forced activated=true` — the toggle flipped the composer to agentic;
44
+ 2. `ui_driver.bound mode=agentic` — the agentic driver was bound;
45
+ 3. exit 0;
46
+ 4. exactly `-Count` `.jpg` files written (scrape → dedup-by-UUID → download).
47
+
48
+ Run it directly without the harness, too:
49
+
50
+ ```powershell
51
+ $env:GFLOW_CLI_FORCE_AGENT_UI="1"
52
+ uv run gflow image t2i "a ripe banana on a white plate" --profile denon82 --json
53
+ ```
54
+
55
+ > `GFLOW_CLI_FORCE_AGENT_UI` is a **testing/diagnostic opt-in**, not a user
56
+ > feature: it forces the agentic path even when the server served classic.
57
+ > Leave it unset for normal use (the cohort is then auto-detected per
58
+ > generation).
59
+
60
+ ## Validation result (2026-06-14, profile denon82)
61
+
62
+ Forced-agentic runs validated the three assumptions that mocked tests cannot:
63
+
64
+ - **`--count 1`** → exit 0, one **420 KB JPG**. Scrape found the asset, built the
65
+ full-res redirect URL, the `labs.google` download resolved with session
66
+ cookies, and the synthetic `GeneratedImage` fields (`workflow_id=""`, `seed=0`,
67
+ `dimensions=(0,0)`) flowed through the save path without error.
68
+ - **`--count 3`** → exit 0, **3 distinct JPGs** for 3 distinct media UUIDs —
69
+ confirming dedup: the agentic UI's multiple `<img>` nodes per asset collapse to
70
+ the correct count.
71
+
72
+ Classic remains unaffected: live `gflow image t2i` and `gflow video t2v` both
73
+ succeed when the cohort/loads serve classic.
74
+
75
+ ## Knowledge extracted (this cost real e2e runs — keep it)
76
+
77
+ Three render-timing / detection bugs were found **only** by live e2e (mocked
78
+ tests passed throughout); each is now fixed with a regression test:
79
+
80
+ 1. **Cohort detection raced the render.** `get_ui_driver` probed instantly after
81
+ navigation and missed the agentic `tune` indicator (it appeared ~1.25 s
82
+ later), defaulting to classic → spurious `FlowAgentUiError` (exit 25). Fix:
83
+ `detect_ui_mode` polls (8 s window). Test: `test_detect_agentic_after_delayed_render`.
84
+ 2. **The force-toggle raced the render too.** `_force_agent_mode` probed for the
85
+ Agent toggle ~0.8 s after entering the editor, before the composer rendered →
86
+ `agent_toggle_not_found`, silently staying classic. Fix: `wait_for` the toggle
87
+ (8 s) before clicking.
88
+ 3. **Content-policy detection false-positived on static chrome.** Scanning the
89
+ whole `document.body` for "content policy" matched a benign page's footer/menu
90
+ link → every agentic generation died with a spurious `ContentPolicyError`
91
+ (exit 5) in ~6 s. Fix: scope the scan to `[role=alert]`/`[role=dialog]`/
92
+ `[aria-live=assertive]` regions only (a real block surfaces there; a
93
+ chat-message-only refusal is missed, which is the safe trade — a miss →
94
+ timeout beats a false positive that breaks every generation). Tests:
95
+ `test_await_images_raises_content_policy_on_explicit_text`,
96
+ `test_await_images_ignores_body_chrome_policy_text`.
97
+
98
+ General lesson: **any agentic-composer probe must wait for the render** — instant
99
+ DOM checks race Flow's deferred composer mount.
100
+
101
+ ## Still owed
102
+
103
+ - A **captured positive content-policy refusal** in the agentic cohort, to widen
104
+ detection safely beyond alert/dialog regions (chat-message refusals are
105
+ currently missed → timeout). Trigger a disallowed prompt under
106
+ `GFLOW_CLI_FORCE_AGENT_UI=1` and capture how the refusal surfaces.
107
+ - **Agentic video** — only the image path is validated; video stays on the
108
+ classic→`FlowAgentUiError` path pending a video scraping capture.
@@ -0,0 +1,192 @@
1
+ # Agentic Flow UI — Recon Findings
2
+
3
+ > Reverse-engineered 2026-06-14 via `gflow-agent-browser-spike` (CDP-attached
4
+ > real Chrome, `agent-browser@0.27.0`) against the live Flow editor on two
5
+ > Chrome profiles. Account-specific values (emails, project UUIDs) are redacted.
6
+ > Relates to issues #183 (image `t2i` exit 23) and #174 (library-UI entity drop).
7
+
8
+ ## TL;DR
9
+
10
+ - Flow runs a **server-side A/B cohort** that swaps the project composer between
11
+ the **classic** media UI and a new **agentic** UI (chat-style "Agent").
12
+ - It is **volatile**: the *same* Chrome profile rendered the classic composer at
13
+ one point and the agentic composer later on the *same* project — confirming the
14
+ #174 flapping (denon82 reverting within 12h).
15
+ - **gflow's own dedicated automation profiles DO land in the agentic cohort**
16
+ (not only the user's primary profile), so #183/#174 are reproducible through
17
+ gflow — the feature must handle it.
18
+ - The cohort is **NOT discoverable from client-side state**: localStorage keys and
19
+ JS-visible cookies are byte-identical across both UIs, and the prime-suspect key
20
+ `FLOW_MAIN_PROMPT_BOX_STATE` holds only generation settings, not a mode flag.
21
+ → **Detection must be runtime DOM-based**; there is no pre-navigation cookie/flag
22
+ to read or flip.
23
+ - `navigator.webdriver` is **`false`** under CDP-attached real Chrome.
24
+
25
+ ## How it was captured
26
+
27
+ `gflow-agent-browser-spike` launches real Chrome with `--remote-debugging-port`
28
+ on a chosen profile and drives `agent-browser` over CDP. JS is passed as
29
+ **base64-wrapped `eval`** (`eval(atob('…'))`) — multi-line eval args get mangled
30
+ through `npx`, so base64 is the reliable path (this also applies to
31
+ `capture-agent-ui.ps1`, which must minify/encode its eval expressions). Capturing
32
+ the user's **primary** profile required relaunching it with the debug flag (only
33
+ applied on a fresh Chrome start, so all windows must be closed first), which
34
+ triggered a one-time Google 2-Step Verification.
35
+
36
+ ## The two UIs — DOM signature
37
+
38
+ | Signal | Classic | Agentic |
39
+ |---|---|---|
40
+ | `crop_*` inline aspect/mode trigger | **present** (`crop_9_16` etc.) | **absent** |
41
+ | Agent pill (`/\bAgent\b/` + `div[role='textbox']`) | no | **yes** |
42
+ | Chat ligatures `edit_square`, `thumb_up`, `thumb_down`, `flag` | no | **yes** |
43
+ | Agentic ligatures `article_spark`, `apps_spark_2`, `tune` | no | **yes** |
44
+ | "What do you want to create?" placeholder | no | **yes** |
45
+ | Aspect / model / upscale controls | inline `crop_*` dropdown | moved into **"Agent settings"** (`tune`) |
46
+
47
+ Agentic ligature inventory (captured): `accessibility_new, add, add_2,
48
+ apps_spark_2, arrow_back, arrow_forward, arrow_forward_ios, article_spark, close,
49
+ content_copy, dashboard, delete, edit_square, filter_list, flag, help, image,
50
+ left_panel_close, menu, more_vert, movie, search, settings_2, thumb_down,
51
+ thumb_up, tune, warning` — and **no `crop_*`**.
52
+
53
+ ## Gating mechanism (the cohort key)
54
+
55
+ Captured on agentic profiles (both the user's primary and a gflow dedicated
56
+ profile), the client-visible state is **identical**:
57
+
58
+ - **localStorage keys**: `FLOW_MAIN_PROMPT_BOX_STATE`, `FLOW_QUICK_SEARCH_MODE`,
59
+ `_grecaptcha`, `glue.CookieNotificationBar`, `nextauth.message`.
60
+ - **JS-visible cookies**: `EMAIL`, `_ga`, `_ga_X2GNH8R5NS` (any cohort cookie
61
+ would be `httpOnly`, i.e. invisible to JS — recoverable only from HAR request
62
+ headers, not yet captured).
63
+ - **`FLOW_MAIN_PROMPT_BOX_STATE`** value (agentic):
64
+ `{"aspectRatio":"PORTRAIT","selectedImageModelFamily":"narwhal_display","selectedVideoModelFamily":"abra","imageOrVideoMode":"IMAGE","outputsPerPrompt":1,"selectedVideoDuration":4}`
65
+ — generation settings only, **no cohort/mode flag**.
66
+
67
+ Because (a) the key set is identical across classic and agentic, (b) the one
68
+ plausible key holds only settings, and (c) the same profile flaps between states,
69
+ the cohort is concluded to be **server-assigned per page load**, not a readable
70
+ client signal. Pre-navigation detection (read a cookie before driving) is **not
71
+ viable**; runtime DOM classification is the only reliable detector.
72
+
73
+ ## Why the existing handling fails (#183)
74
+
75
+ `_exit_agent_mode` (`ui_automation_video.py`) assumes the classic composer is
76
+ recoverable and keys on `_media_panel_present` (the `crop_*` trigger). In the
77
+ agentic cohort there is **no `crop_*`** at all (aspect moved into Agent settings),
78
+ so the probe never recovers, the selector cascade exhausts, and the caller raises
79
+ `UiSelectorDriftError` (exit 23). The recovery has nothing to recover *to*.
80
+
81
+ ## Recommendation for the feature plan
82
+
83
+ 1. **Detection = runtime DOM classification.** Agentic if *no `crop_*` mode
84
+ trigger* **and** (*Agent pill present* **or** *chat-panel ligatures present*).
85
+ This is what `classify_composer` / a refreshed `_exit_agent_mode` should key
86
+ on. Run it every generation — the cohort flaps, so no caching.
87
+ 2. **No pre-flight cookie/flag gate** — there is no client-readable cohort signal.
88
+ 3. **Response (decide in the feature plan, evidence now supports either):**
89
+ - **Detect + fail cleanly** with a typed `FlowAgentUiError` (own exit code) +
90
+ screenshot — low risk, immediately diagnosable. *Recommended first step.*
91
+ - **Drive the agentic surface** — type into the chat composer, set aspect/model
92
+ via the Agent-settings (`tune`) panel, handle the confirm-before-generating
93
+ gate. Larger; intermittently needed because the cohort flaps.
94
+
95
+ ## DOM scraping validation (2026-06-14, live capture)
96
+
97
+ > Captured via `scripts/capture-media-scrape.ps1` (CDP-attached real Chrome,
98
+ > profile `default`, agentic cohort confirmed: `crop=false, agentPill=true,
99
+ > chatPanel=true`). One image generation, before/after media-DOM snapshot.
100
+ > Artifact: `media-scrape-agentic-20260614-202739.json`.
101
+
102
+ This resolves the open question blocking `AgenticFlowUiDriver.await_images`: **how do
103
+ generated assets surface in the agentic DOM, and is count-delta scraping viable?**
104
+
105
+ - **Assets render as plain remote `<img>` nodes.** After the generation: `blob=0`,
106
+ `data=0`, `canvas=0`, `background-image=0`. The full-res asset is a normal
107
+ `<img src="https://…">`. Count-delta DOM scraping **is viable** — network
108
+ interception is not (see HAR note below).
109
+ - **The src is a same-origin tRPC redirect carrying a stable media id:**
110
+ ```
111
+ https://labs.google/fx/api/trpc/media.getMediaUrlRedirect?name=<uuid>[&mediaUrlType=MEDIA_URL_TYPE_THUMBNAIL]
112
+ ```
113
+ It 302-redirects to the CDN blob; same-origin (`labs.google`) means the session
114
+ cookies authorize the download. The `name=<uuid>` is the **stable backend media id**
115
+ — scraped assets correlate to media identity (usable for the batch ledger / dedup).
116
+ - **Dedupe by `name=<uuid>`, NOT by `<img>` node count.** One generated asset surfaces
117
+ as **multiple** `<img>` nodes (canvas full-res + filmstrip thumbnail + chat preview,
118
+ each in bare and `&mediaUrlType=MEDIA_URL_TYPE_THUMBNAIL` variants). The single
119
+ capture produced **9 new `<img>` nodes for only 3 distinct assets** (~3× inflation).
120
+ `await_images` must extract the `name` query param and **count distinct UUIDs** — a
121
+ raw `initial_count + expected_count` node check would massively over-count.
122
+ - **Page-level HAR captured 0 entries.** Confirms the Web-Worker delegation: the
123
+ `streamChat` + media requests bypass page-level network capture entirely. **DOM
124
+ scraping is the only viable capture path** in the agentic cohort.
125
+ - **`flag` is NOT a content-policy signal.** The warn-symbol probe matched the `flag`
126
+ ligature 11× on a *successful* generation — `flag`/`thumb_up`/`thumb_down` are the
127
+ normal per-message chat affordances. Fail-fast detection must key on `warning` /
128
+ `error` / `block` or specific dialog/stream text, **never `flag`**. *(A deliberate
129
+ content-policy-refusal capture is still outstanding — no positive block sample yet.)*
130
+
131
+ ## Settings via prompt, not the `tune` popover (agentic acts MCP-like)
132
+
133
+ The agentic composer behaves like a conversational agent: generation parameters that the
134
+ classic UI exposes as discrete controls — **output count** (1 / 4 images), **video
135
+ duration** (4/6/8/10 s), and likely **aspect ratio** and **model** — can be expressed in
136
+ **natural language inside the prompt** (e.g. `Generate 4 images of <prompt> in 16:9`), and
137
+ the agent resolves the selection itself.
138
+
139
+ Implications for `AgenticFlowUiDriver`:
140
+ - **`configure_settings` becomes optional.** Encoding settings as a directive prompt
141
+ avoids driving the fragile `tune` → Radix-popover dropdowns — the most drift-prone
142
+ surface on a volatile A/B UI. Prefer prompt-encoding; treat popover automation as a
143
+ fallback only if prompt-steering proves unreliable.
144
+ - **The agent *interprets* the request → verify, don't trust.** It may produce a
145
+ different count or ignore a duration. This is precisely why scrape-and-dedup-by-UUID
146
+ is load-bearing: request N → poll until N distinct new media UUIDs → if the produced
147
+ count differs, raise a typed mismatch rather than silently returning the wrong set.
148
+ - **Compose carefully** so settings directives aren't read as subject text (e.g. a
149
+ `Generate {n} image(s){aspect}: {prompt}` template).
150
+
151
+ ## Open follow-ups
152
+
153
+ - **Content-policy block sample (outstanding):** capture a deliberate-refusal generation
154
+ in the agentic cohort to learn how a block surfaces (chat message vs. dialog vs.
155
+ symbol) — needed to design `await_images` fail-fast. The `flag` symbol is ruled out.
156
+
157
+ ## The Wire & API Endpoint (Resolved via Issue #183 Reporter)
158
+
159
+ The network request logs from the agentic UI have been resolved. The new UX bypasses the direct media generation endpoints (such as `batchGenerateImages`) and routes all generation requests through Google's conversational flow creation agent.
160
+
161
+ - **Endpoint**: `POST https://aisandbox-pa.googleapis.com/v1/flowCreationAgent:streamChat?alt=sse`
162
+ - **Transport**: Server-Sent Events (SSE) stream, preceded by a CORS OPTIONS preflight.
163
+ - **Request Payload Structure**:
164
+ ```json
165
+ {
166
+ "agentSessionId": "<uuid>",
167
+ "agentClientContext": {
168
+ "projectId": "projects/<projectUuid>",
169
+ "clientSessionId": ";<epochMillis>",
170
+ "recaptchaContext": {
171
+ "token": "<recaptcha_token>",
172
+ "applicationType": "RECAPTCHA_APPLICATION_TYPE_WEB"
173
+ },
174
+ "turnNumber": 2
175
+ },
176
+ "userMessage": {
177
+ "userPrompt": {
178
+ "parts": [
179
+ {
180
+ "text": "a red apple"
181
+ }
182
+ ]
183
+ }
184
+ }
185
+ }
186
+ ```
187
+
188
+ ### Why page-level CDP/Playwright instrumentation recorded 0 entries
189
+ During local capture sessions, page-level request event listeners repeatedly recorded `0` API request entries. This occurred because the agentic UI delegates all `streamChat` network requests to a background **Web/Service Worker** target (`type: worker`). Worker-initiated requests completely bypass page-level network event registration in Playwright/CDP and require worker-level target attachments to capture.
190
+
191
+ ### Impact on issue #174 (referenceEntities)
192
+ In the agentic UI, the prompt box is a conversational Slate.js editor. Because generation is driven by the conversation agent stream rather than direct REST inputs, staging library entities (e.g. characters) behaves differently. For the initial implementation phase, driving or injecting into `flowCreationAgent:streamChat` is out of scope. The recommended direction is **Runtime DOM detection + Fail Cleanly** with `FlowAgentUiError` (exit code 23) to prevent automation lockups while the cohort is active.
@@ -190,6 +190,16 @@ GFLOW_CLI_HISTORY_PROMPTS=redacted gflow image t2i "confidential brief"
190
190
  **Default:** `true`
191
191
  **When to flip to `false`:** if reCAPTCHA Enterprise refuses to mint tokens (Google's bot-detection sometimes refuses headless Chromium but accepts a visible window). Set to `false` and re-run; the browser will appear during generation but the session is still reused from the persistent profile.
192
192
 
193
+ ### `GFLOW_CLI_BROWSER_ENGINE`
194
+
195
+ **What:** Selects the browser-automation engine backing the Playwright API.
196
+ **Values:** `playwright` | `patchright`
197
+ **Default:** `playwright`
198
+ **What `patchright` is:** an opt-in, drop-in patched Playwright (Chromium) that runs page evaluations in an isolated execution context to avoid the `Runtime.enable` CDP leak, for stronger reCAPTCHA-Enterprise evasion on the **headed** path. It is **not** a headless unlock — Google still detects headless Chromium regardless of engine.
199
+ **Install:** `pip install 'gflow-cli[patchright]'` (or `pip install patchright`). Selecting `patchright` without it installed fails fast with exit code 24 and a pip remediation hint. When using system Chrome (the gflow default, `channel=chrome`) you do **not** need `patchright install chromium`.
200
+ **Reverting:** unset the variable (or set `playwright`) — the default path is byte-identical to a build without this feature, with no profile migration.
201
+ **Security note:** the `patchright` extra ships a *patched Chromium driver* that handles your live Google session cookies; it is exact-pinned and treated as a security-review-required dependency. See [SECURITY.md § Dependencies](SECURITY.md).
202
+
193
203
  ### `GFLOW_CLI_LOCALE`
194
204
 
195
205
  **What:** BCP-47 locale tag passed to Playwright's `launch_persistent_context(locale=...)` — controls the `Accept-Language` HTTP header only.
@@ -35,6 +35,7 @@ Welcome to the `gflow-cli` documentation. This index is the routing layer: it te
35
35
  | **[docs/CHARACTER.md](CHARACTER.md)** | Characters feature spec & system design: domain model, endpoint/cost matrix, sequence diagrams, JSON payloads (I/O), CLI surface, reuse via `referenceEntities` (#145) | Working on `gflow character`, reusing a character in generations, or understanding Flow's character wire protocol |
36
36
  | **[docs/MOVIE.md](MOVIE.md)** | `gflow movie` — multi-scene character-consistent films: manifest format, run lifecycle (browser stays open through generate→poll→download), entity-attach mechanism (Personagens right-click), resume/handoff, credits | Working on `gflow movie`, debugging scene generation, or understanding the character-entity attach + consistency model |
37
37
  | **[docs/IMAGE_UPSCALE_RECON.md](IMAGE_UPSCALE_RECON.md)** | `gflow image upscale` wire protocol: `upsampleImage` endpoint, full clientContext (projectId/sessionId/tool/userPaygateTier), reCAPTCHA action `IMAGE_GENERATION`, inline base64 response, 4K Ultra-gating, REST-is-dead proof | Working on `gflow image upscale`, debugging the 403/reCAPTCHA path, or understanding Flow's image-upscale wire protocol (#171) |
38
+ | **[docs/AGENT_UI_RECON.md](AGENT_UI_RECON.md)** | Agentic Flow UI cohort: classic-vs-agentic DOM signature, server-side + volatile (flapping) A/B gating (no client-readable flag), why `_exit_agent_mode` fails, runtime-DOM-detection recommendation | Touching `_exit_agent_mode` / composer mode-switch, diagnosing exit 23 selector drift, or understanding Flow's agentic-UI A/B (#183/#174) |
38
39
  | **[tasks/lessons.md](../tasks/lessons.md)** | Running notebook of patterns + reviewer findings, dated and traced to commits | Starting a new phase; debugging "why did the council flag this?" |
39
40
  | **[skills/README.md](../skills/README.md)** | Installable agent skill docs (gflow-cli, predict, pr-council-review, scenario) — cross-tool portable Markdown consumed by Claude Code, Cursor, Codex, Gemini CLI, Aider, etc. | Any agent wanting to use gflow-cli correctly |
40
41
  | **[scripts/dev/skillopt/README.md](../scripts/dev/skillopt/README.md)** | SkillOpt mock harness — rollout→score loop for measuring and improving skill doc accuracy across multiple LLM providers | Measuring a skill edit's impact; comparing Claude vs GPT-4o vs Gemini on gflow tasks |
@@ -111,7 +112,7 @@ Slash commands for Claude Code, stored in `.claude/commands/gflow/`. All prefixe
111
112
  **"A gflow command hangs / fails — where do I start?"** → [DEBUGGING § Quick reference](DEBUGGING.md#quick-reference)
112
113
  **"Flow's UI broke a selector — how do I diagnose it?"** → [DEBUGGING § Inspecting Flow's live UI](DEBUGGING.md#inspecting-flows-live-ui)
113
114
  **"What does each `ui_automation.*` log event mean?"** → [DEBUGGING § Listener & HTTP-layer debugging](DEBUGGING.md#listener--http-layer-debugging)
114
- **"What was actually live-verified for the latest release?"** → latest: [LIVE_VERIFICATION_v0.18.0](LIVE_VERIFICATION_v0.18.0.md) (#183 exit-23 selector-drift error: live drift simulation + happy path, credit-free). v0.14.0 / v0.15.0 / v0.15.1 shipped without a dedicated doc (CI + the v0.13.0 baseline). Prior: [v0.17.0](LIVE_VERIFICATION_v0.17.0.md) · [v0.16.0](LIVE_VERIFICATION_v0.16.0.md) · [v0.13.0](LIVE_VERIFICATION_v0.13.0.md) · [v0.12.0](LIVE_VERIFICATION_v0.12.0.md) · [v0.11.0](LIVE_VERIFICATION_v0.11.0.md) · [v0.10.0](LIVE_VERIFICATION_v0.10.0.md) · [v0.9.1](LIVE_VERIFICATION_v0.9.1.md) · [v0.9.0](LIVE_VERIFICATION_v0.9.0.md) · [v0.8.1](LIVE_VERIFICATION_v0.8.1.md) · [v0.7.0](LIVE_VERIFICATION_v0.7.0.md)
115
+ **"What was actually live-verified for the latest release?"** → latest: [LIVE_VERIFICATION_v0.20.0](LIVE_VERIFICATION_v0.20.0.md) (Agentic UI image generation on `denon82`: classic `image t2i` + `video t2v` unaffected, and forced-agentic `image t2i` count 1 & count 3 with **live dedup-by-UUID** under `GFLOW_CLI_FORCE_AGENT_UI=1`; 5-layer ledger; natural-cohort agentic load + content-policy refusal recorded as not-verified-this-cycle). v0.14.0 / v0.15.0 / v0.15.1 shipped without a dedicated doc (CI + the v0.13.0 baseline). Prior: [v0.19.0](LIVE_VERIFICATION_v0.19.0.md) · [v0.18.0](LIVE_VERIFICATION_v0.18.0.md) · [v0.17.0](LIVE_VERIFICATION_v0.17.0.md) · [v0.16.0](LIVE_VERIFICATION_v0.16.0.md) · [v0.13.0](LIVE_VERIFICATION_v0.13.0.md) · [v0.12.0](LIVE_VERIFICATION_v0.12.0.md) · [v0.11.0](LIVE_VERIFICATION_v0.11.0.md) · [v0.10.0](LIVE_VERIFICATION_v0.10.0.md) · [v0.9.1](LIVE_VERIFICATION_v0.9.1.md) · [v0.9.0](LIVE_VERIFICATION_v0.9.0.md) · [v0.8.1](LIVE_VERIFICATION_v0.8.1.md) · [v0.7.0](LIVE_VERIFICATION_v0.7.0.md)
115
116
  **"Where is the reverse-engineered wire protocol for a feature?"** → the `*_RECON.md` design docs: [CHARACTER_RECON](CHARACTER_RECON.md) (Flow character entity protocol), [IMAGE_UPSCALE_RECON](IMAGE_UPSCALE_RECON.md) (`/v1/flow/upsampleImage` wire). Naming convention: one `<FEATURE>_RECON.md` per reverse-engineered surface, kept as the durable spec after the feature ships.
116
117
  **"What was live-verified for the data layer (PR #58)?"** → [LIVE_VERIFICATION_data_layer](LIVE_VERIFICATION_data_layer.md) — 1 Imagen + 1 Veo credit on denon82, 6-layer ledger (file + magic + Pillow + DB rows + CLI round-trip + structlog)
117
118
  **"What was live-verified for the video-download feature (#29)?"** → [LIVE_VERIFICATION_video_download](LIVE_VERIFICATION_video_download.md)
@@ -0,0 +1,60 @@
1
+ # Live Verification — v0.19.0
2
+
3
+ Feature under test: **opt-in Patchright browser engine** (`GFLOW_CLI_BROWSER_ENGINE=patchright`).
4
+ Verified 2026-06-12 against live Google Flow on a real authenticated profile. Image
5
+ generation is credit-free, so the end-to-end run cost **$0**.
6
+
7
+ ## Layer 1 — file count
8
+
9
+ One image produced by `gflow image t2i` through the integrated patchright path:
10
+
11
+ ```
12
+ scripts/dev/_spike_out/patch_verify/images/2026-06-12/6cb21d9e-e4f9-40ba-897c-eb25c6333892_1.jpg
13
+ ```
14
+
15
+ (written to a throwaway `GFLOW_CLI_OUTPUT_DIR`, since cleaned up).
16
+
17
+ ## Layer 2 — magic bytes
18
+
19
+ `b[:3] == FF D8 FF` → **valid JPEG**. Size 723,911 bytes.
20
+
21
+ ## Layer 3 — dimensions / shape
22
+
23
+ Pillow: `format=JPEG dims=(768, 1376)` → correct **9:16** portrait (the default aspect).
24
+
25
+ ## Layer 4 — structlog invariants
26
+
27
+ From the live run (`correlation_id=40877345-0af4-472f-966a-94f88112f0d9`):
28
+
29
+ - `browser.engine_selected engine=patchright` — the **settings resolver** selected
30
+ patchright (the real wired path, not a test monkeypatch).
31
+ - `ui_automation.batch_request_body` — prompt submitted (`bytes=5054`).
32
+ - `ui_automation.batch_response_seen status=200` and
33
+ `ui_automation.batch_response_captured status=200` — `batchGenerateImages`
34
+ returned 200 and the response body parsed under patchright.
35
+
36
+ ## Layer 5 — user-confirmable artifact
37
+
38
+ A studio-lit image of "a small green cactus in a terracotta pot" — visually
39
+ inspectable, matches the prompt.
40
+
41
+ ## Supporting checks (same release)
42
+
43
+ | Check | Evidence | Result |
44
+ |---|---|---|
45
+ | Default path byte-identical | client-level `navigator.webdriver` read through real `FlowApiClient`: `playwright → None` (masked), `patchright → False` (both non-bot) | ✅ default still stealthed |
46
+ | Missing-dependency UX | `GFLOW_CLI_BROWSER_ENGINE=patchright` with patchright uninstalled → `image t2i` | ✅ **exit 24**, `BrowserEngineUnavailableError` + `pip install patchright` hint, no traceback, no browser launched |
47
+ | Invalid enum setting | `GFLOW_CLI_BROWSER_ENGINE=patchwright` (and `GFLOW_CLI_PROVIDER=bogus`) | ✅ **exit 11**, clean "Configuration error" naming the variable, no raw pydantic traceback |
48
+ | reCAPTCHA mint under patchright | `TokenMinter.mint` with `isolated_context=False` | ✅ returns a real token (the predicted isolated-world break, fixed) |
49
+ | Retry across engine boundary | patchright's distinct `TimeoutError` through the real retry policy | ✅ retried (unit test) |
50
+
51
+ ## Premise still pending (documented, not a blocker)
52
+
53
+ The *value* premise — does patchright reduce real 403s vs Playwright — could **not**
54
+ be measured this cycle: the documented hot profile (`denon82`) had cooled, so plain
55
+ Playwright also returned 200 (no 403 to flip). A faithful 403 cannot be emulated
56
+ locally (a route-injected 403 is engine-blind; inflating real WAF heat risks the
57
+ account). The feature ships as a **proven non-breaking, opt-in escape-hatch** with
58
+ the default unchanged. Re-fire trigger: the instant any profile actually 403s, run
59
+ `scripts/dev/spike_patchright.py --profile <hot> --engines playwright,patchright`
60
+ to capture the `WAF_403 → OK_200` differential.
@@ -0,0 +1,76 @@
1
+ # Live verification — v0.20.0 (Agentic UI driver)
2
+
3
+ > Hand-run against the real Google Flow editor on profile `denon82`. v0.20.0
4
+ > ships the pluggable `FlowUiDriver` strategy and **Agentic-cohort image
5
+ > generation**. The agentic cohort is server-assigned and cannot be forced from
6
+ > the client, so the deterministic trigger `GFLOW_CLI_FORCE_AGENT_UI=1` (clicks
7
+ > the in-input "Agent" toggle) is used to exercise the agentic path. Image
8
+ > generation is credit-free.
9
+
10
+ ## Environment
11
+
12
+ | | |
13
+ |---|---|
14
+ | Branch | `feature/agentic-ui-driver` → `develop` (PR [#189](https://github.com/ffroliva/gflow-cli/pull/189)) |
15
+ | Version | `0.19.0` working tree (pre-v0.20.0 bump) |
16
+ | Profile | `denon82` (real-browser Chrome) |
17
+ | Profile dir | `C:\Users\ffrol\AppData\Local\ffroliva\gflow-cli\profile_denon82` |
18
+ | Date | 2026-06-14 |
19
+ | Transport | `ui_automation` |
20
+ | Engine | `playwright` |
21
+
22
+ ## How to reproduce
23
+
24
+ ```pwsh
25
+ $env:PYTHONUTF8=1
26
+ # Classic cohort (auto-detected):
27
+ uv run gflow image t2i "a red apple on a rustic wooden table" --profile denon82 --aspect 16:9 --json
28
+ uv run gflow video t2v "a golden sunset over calm ocean waves" --profile denon82 --aspect 16:9 --duration 4 --json
29
+
30
+ # Agentic cohort, forced deterministically (clicks the Agent toggle):
31
+ $env:GFLOW_CLI_FORCE_AGENT_UI="1"
32
+ uv run gflow image t2i "a single ripe banana on a white plate" --profile denon82 --aspect 16:9 --json
33
+ uv run gflow image t2i "three colorful macarons on a marble surface" --profile denon82 --count 3 --json
34
+
35
+ # Deterministic harness (verifies forced→agentic→scrape→download, asserts file count):
36
+ .\scripts\e2e\agentic_image_e2e.ps1 -Profile denon82 -Count 3
37
+ ```
38
+
39
+ ## Evidence ledger (5-layer)
40
+
41
+ Each run: **file written** + **magic bytes (JPEG/MP4)** + **dimensions/size** +
42
+ **structlog invariants** + **user-confirmable artifact (media UUID + path)**.
43
+
44
+ | # | Path | Cohort | Result | Media UUID(s) | Bytes | Key structlog invariants |
45
+ |---|---|---|---|---|---|---|
46
+ | 1 | image t2i (classic) | classic | exit 0, 1 JPG | `f3e529ca…` | 647 KB | `ui_driver.bound mode=classic`; `crop_16_9` matched; `batchGenerateImages` 200 captured |
47
+ | 2 | video t2v (classic) | classic | exit 0, 1 MP4 | `433a92d5…` | 6.33 MB | `video_mode_entered`; `poll_terminal STATUS_SUCCESSFUL`; `video_saved` |
48
+ | 3 | image t2i (forced agentic, count 1) | agentic | exit 0, 1 JPG | `3722b716…` | 420 KB | `agent_mode_forced activated=true`; `ui_driver.bound mode=agentic`; full-res `getMediaUrlRedirect` URL |
49
+ | 4 | image t2i (forced agentic, count 3) | agentic | exit 0, **3 distinct** JPGs | `0bfb4127…`, `2f5c5f9e…`, `cd8f4781…` | 596 / 590 / 629 KB | `mode=agentic`; **dedup**: multiple `<img>` nodes → 3 distinct media UUIDs |
50
+
51
+ ## What this proves
52
+
53
+ - **Classic path unaffected** by the driver refactor (rows 1–2): image + video
54
+ generate and download end-to-end through the new `ClassicFlowUiDriver`.
55
+ - **Agentic image generation works end-to-end** (rows 3–4): the Agent toggle
56
+ flips the composer to agentic, the agentic driver encodes settings into the
57
+ prompt, types into the Slate composer, **scrapes** the generated assets from
58
+ the DOM (page-level network capture is dead in this cohort — Web-Worker
59
+ delegated), **deduplicates by media UUID**, and downloads via the same-origin
60
+ `labs.google/.../getMediaUrlRedirect` redirect (allow-listed for download).
61
+ - **Synthetic `GeneratedImage` fields** (`seed=0`, `workflow_id=""`,
62
+ `dimensions=(0,0)`) flow through the save/report path without error.
63
+
64
+ ## Not verified this cycle (recorded honestly)
65
+
66
+ - **A natural (non-forced) agentic load end-to-end:** the cohort flapped to
67
+ classic during the windows tested; the forced path exercises identical driver
68
+ code, but a naturally-served agentic load was not captured generating.
69
+ - **A positive content-policy refusal in the agentic cohort:** detection is
70
+ scoped to alert/dialog regions pending a captured sample (a chat-message-only
71
+ refusal currently misses → timeout). See `docs/AGENT_UI_E2E.md`.
72
+ - **Agentic video:** out of scope — raises `FlowAgentUiError` (exit 25) pending a
73
+ video scraping capture.
74
+
75
+ See [docs/AGENT_UI_E2E.md](AGENT_UI_E2E.md) for the repeatable procedure and the
76
+ three render-race / detection bugs this live testing surfaced and fixed.
@@ -201,6 +201,26 @@ Audited with `pip-audit` in CI on every push. Major dependency surface:
201
201
 
202
202
  No transitive dep with known CVEs at the time of v0.1.0 scaffold.
203
203
 
204
+ ### Optional `patchright` engine — elevated supply-chain trust
205
+
206
+ The `gflow-cli[patchright]` extra (opt-in via `GFLOW_CLI_BROWSER_ENGINE=patchright`)
207
+ installs **Patchright**, a single-maintainer package that ships a **patched
208
+ Chromium driver**. Because that driver *is* the browser process that loads your
209
+ real Google session — it has direct access to session cookies, the OAuth Bearer
210
+ token, and SAPISID — it carries a higher blast radius than an ordinary Python
211
+ dependency: a compromised release could exfiltrate the full Google session.
212
+
213
+ Controls:
214
+
215
+ - **Optional-only** — never in the base `dependencies`; the default install pulls
216
+ neither the package nor its driver.
217
+ - **Exact-pinned** (`patchright==1.60.1`) so a release cannot silently move the
218
+ browser binary underneath you.
219
+ - **Security-review-required on bump** — a Patchright version change is treated
220
+ like a browser-binary change, NOT a routine dependabot auto-merge.
221
+ - Default engine is `playwright` (Microsoft, security-reviewed); patchright is an
222
+ experiment you opt into per the trade-off above.
223
+
204
224
  ## Reporting
205
225
 
206
226
  | Issue type | How |
@@ -1031,6 +1031,7 @@ shell scripts can branch on the failure mode without parsing stderr.
1031
1031
  | `21` | `ChainPartialError` | A video chain stopped mid-way; earlier links completed | Resume from the last completed link shown in the error |
1032
1032
  | `22` | `UpscaleUnavailableError` | 4K upscale is gated to Flow **Ultra** accounts (HTTP 403) | Use `--scale 2k`, or upgrade the Flow plan |
1033
1033
  | `23` | `UiSelectorDriftError` | A Flow editor control could not be located — Google changed the frontend (issue #183) | Update gflow-cli; file a bug with the probe name + debug screenshot from the error message |
1034
+ | `24` | `BrowserEngineUnavailableError` | `GFLOW_CLI_BROWSER_ENGINE=patchright` but the engine is not installed | `pip install 'gflow-cli[patchright]'`, or unset `GFLOW_CLI_BROWSER_ENGINE` |
1034
1035
  | `130`| SIGINT | User-interrupted (Ctrl-C) | — |
1035
1036
 
1036
1037
  **Exit code 16 — data store / migration error.** Fires when:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "gflow-cli"
3
- version = "0.18.0"
3
+ version = "0.20.0"
4
4
  description = "Unofficial CLI for Google Flow — drive Veo image-to-video generations from the terminal."
5
5
  readme = "README.md"
6
6
  license = { file = "LICENSE" }
@@ -58,6 +58,15 @@ s3 = [
58
58
  chain = [
59
59
  "av>=12",
60
60
  ]
61
+ # Patchright engine extra — opt-in, drop-in patched Playwright (Chromium) that
62
+ # avoids the Runtime.enable CDP leak on the headed path. Selected via
63
+ # GFLOW_CLI_BROWSER_ENGINE=patchright. Ships a PATCHED Chromium driver that
64
+ # handles live Google session cookies/Bearer/SAPISID, so it is EXACT-pinned and
65
+ # treated as a security-review-required bump (NOT a dependabot auto-merge) —
66
+ # see SECURITY.md. Not a headless unlock.
67
+ patchright = [
68
+ "patchright==1.60.1",
69
+ ]
61
70
 
62
71
  [project.scripts]
63
72
  gflow = "gflow_cli.cli:main"