gflow-cli 0.5.0a1__tar.gz → 0.6.0a2__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 (178) hide show
  1. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/.gitattributes +4 -2
  2. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/.gitignore +1 -0
  3. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/CHANGELOG.md +98 -3
  4. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/CLAUDE.md +63 -0
  5. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/KNOWN_ISSUES.md +29 -0
  6. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/PKG-INFO +23 -2
  7. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/PLAN.md +22 -6
  8. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/README.md +22 -1
  9. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/ARCHITECTURE.md +38 -1
  10. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/AUTHENTICATION.md +28 -4
  11. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/USAGE.md +36 -4
  12. gflow_cli-0.6.0a2/docs/assets/example-run.gif +0 -0
  13. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/2026-05-14-shell-multi-prompt-orchestration.md +165 -0
  14. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_FINAL_ARCH.md +34 -0
  15. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_FINAL_SEC_UX.md +47 -0
  16. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_CODE.md +46 -0
  17. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_GEMINI.md +89 -0
  18. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_SECURITY.md +70 -0
  19. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/IMPLEMENTATION_REVIEW_PYTHON.md +37 -0
  20. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/IMPLEMENTATION_REVIEW_SECURITY.md +33 -0
  21. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN.md +1919 -0
  22. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_CODE.md +70 -0
  23. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_FOLLOWUP.md +36 -0
  24. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_PLANNER.md +66 -0
  25. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_SECURITY.md +70 -0
  26. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_SECURITY_FOLLOWUP.md +30 -0
  27. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/COUNCIL_FINAL_SEC_UX_VERIFIED.md +30 -0
  28. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/COUNCIL_REVIEW_PLAN_SECURITY.md +57 -0
  29. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/COUNCIL_REVIEW_SPEC_SECURITY.md +37 -0
  30. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/PLAN.md +69 -0
  31. gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/orchestration.md +20 -0
  32. gflow_cli-0.6.0a2/docs/superpowers/specs/2026-05-14-shell-multi-prompt-design.md +497 -0
  33. gflow_cli-0.6.0a2/docs/superpowers/specs/2026-05-15-auth-login-real-chrome-design.md +45 -0
  34. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/examples/README.md +11 -1
  35. gflow_cli-0.6.0a2/examples/multi_prompt_t2i.py +126 -0
  36. gflow_cli-0.6.0a2/examples/sample_prompts.txt +4 -0
  37. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/pyproject.toml +1 -1
  38. gflow_cli-0.6.0a2/scripts/record_demo.ps1 +226 -0
  39. gflow_cli-0.6.0a2/scripts/verify_chrome_auth_viability.py +209 -0
  40. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/__init__.py +1 -1
  41. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/_cli_helpers.py +31 -0
  42. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/_common.py +7 -18
  43. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/_fingerprint.py +4 -12
  44. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/base.py +1 -0
  45. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/experimental/__init__.py +1 -0
  46. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/experimental/bearer.py +6 -13
  47. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/experimental/evaluate_fetch.py +3 -8
  48. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/experimental/sapisidhash.py +9 -13
  49. gflow_cli-0.5.0a1/src/gflow_cli/auth.py → gflow_cli-0.6.0a2/src/gflow_cli/auth/__init__.py +16 -34
  50. gflow_cli-0.6.0a2/src/gflow_cli/auth/base.py +30 -0
  51. gflow_cli-0.6.0a2/src/gflow_cli/auth/factory.py +52 -0
  52. gflow_cli-0.6.0a2/src/gflow_cli/auth/internal_chromium.py +96 -0
  53. gflow_cli-0.6.0a2/src/gflow_cli/auth/real_chrome.py +172 -0
  54. gflow_cli-0.6.0a2/src/gflow_cli/auth/strategies.py +10 -0
  55. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/browser_manager.py +9 -0
  56. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/cli.py +40 -2
  57. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/cli_image.py +192 -33
  58. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/cli_run.py +57 -172
  59. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/cli_video.py +2 -1
  60. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/errors.py +28 -0
  61. gflow_cli-0.6.0a2/src/gflow_cli/image_batch.py +360 -0
  62. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_client.py +2 -6
  63. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_client_image.py +9 -27
  64. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/test_base.py +1 -0
  65. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/test_bearer.py +1 -0
  66. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/test_common.py +3 -0
  67. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/test_evaluate_fetch.py +23 -24
  68. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/test_fingerprint.py +1 -0
  69. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/test_sapisidhash.py +37 -52
  70. gflow_cli-0.6.0a2/tests/auth/strategies/test_factory.py +60 -0
  71. gflow_cli-0.6.0a2/tests/auth/strategies/test_strategies.py +243 -0
  72. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/cli/test_error_handling.py +59 -0
  73. gflow_cli-0.6.0a2/tests/cli/test_t2i_multi_prompt.py +410 -0
  74. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/e2e/test_transports_e2e.py +2 -6
  75. gflow_cli-0.6.0a2/tests/features/auth_login.feature +31 -0
  76. gflow_cli-0.6.0a2/tests/features/image.feature +56 -0
  77. gflow_cli-0.6.0a2/tests/features/test_auth_login_steps.py +127 -0
  78. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/features/test_auth_steps.py +3 -1
  79. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/features/test_image_steps.py +112 -0
  80. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_browser_manager.py +8 -10
  81. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/uv.lock +1 -1
  82. gflow_cli-0.5.0a1/tests/features/image.feature +0 -25
  83. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/.claude/README.md +0 -0
  84. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/.claude/commands/release.md +0 -0
  85. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/.env.template +0 -0
  86. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/.github/workflows/ci.yml +0 -0
  87. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/.github/workflows/release.yml +0 -0
  88. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/.planning/todos/pending/2026-05-11-add-project-logo-and-docs-site-promotion-plan.md +0 -0
  89. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/CONFIGURATION.md +0 -0
  90. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/CONTRIBUTING.md +0 -0
  91. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/DISCLAIMER.md +0 -0
  92. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/LICENSE +0 -0
  93. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/RELEASE.md +0 -0
  94. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/CONFIGURATION.md +0 -0
  95. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/INDEX.md +0 -0
  96. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/SECURITY.md +0 -0
  97. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/USER_GUIDE.md +0 -0
  98. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/superpowers/plans/2026-05-09-image-mvp-orchestration.md +0 -0
  99. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/superpowers/plans/2026-05-09-image-mvp.md +0 -0
  100. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/superpowers/plans/2026-05-09-video-mvp-orchestration.md +0 -0
  101. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/superpowers/plans/2026-05-09-video-mvp.md +0 -0
  102. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/superpowers/plans/2026-05-10-phase-4-hardening-orchestration.md +0 -0
  103. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/superpowers/plans/2026-05-10-phase-4-hardening.md +0 -0
  104. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/superpowers/specs/2026-05-10-phase-4-hardening-design.md +0 -0
  105. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/superpowers/verifications/2026-05-11-phase-4-stage-g.md +0 -0
  106. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/examples/batch_from_config.py +0 -0
  107. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/examples/sample_config.json +0 -0
  108. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/examples/single_image_t2i.py +0 -0
  109. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/samples/README.md +0 -0
  110. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/samples/captured/01_upload_image.json +0 -0
  111. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/samples/captured/02_batchAsyncGenerateVideoText.json +0 -0
  112. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
  113. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/samples/captured/04_archive_workflow.json +0 -0
  114. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/samples/captured/05_createProject.json +0 -0
  115. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/samples/captured/06_batchGenerateImages.json +0 -0
  116. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/samples/captured/07_batchGenerateImages_seeded.json +0 -0
  117. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/scripts/diag_capture_flow_traffic.py +0 -0
  118. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/scripts/diag_recaptcha_mint.py +0 -0
  119. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/scripts/smoke_e2e.py +0 -0
  120. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/scripts/smoke_image.py +0 -0
  121. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/scripts/smoke_real_chrome_image.py +0 -0
  122. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/scripts/smoke_worker_style.py +0 -0
  123. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/skills/README.md +0 -0
  124. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/skills/gflow-cli/SKILL.md +0 -0
  125. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/__main__.py +0 -0
  126. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/__init__.py +0 -0
  127. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/_retry.py +0 -0
  128. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/client.py +0 -0
  129. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/dto.py +0 -0
  130. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/image.py +0 -0
  131. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/recaptcha.py +0 -0
  132. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/routes.py +0 -0
  133. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/__init__.py +0 -0
  134. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/ui_automation.py +0 -0
  135. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/video.py +0 -0
  136. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/config.py +0 -0
  137. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/manifest.py +0 -0
  138. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/observability.py +0 -0
  139. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/paths.py +0 -0
  140. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/profile_store.py +0 -0
  141. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tasks/lessons.md +0 -0
  142. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/__init__.py +0 -0
  143. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/__init__.py +0 -0
  144. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_client_generate_video.py +0 -0
  145. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_concurrency.py +0 -0
  146. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_dto.py +0 -0
  147. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_image.py +0 -0
  148. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_image_dto.py +0 -0
  149. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_recaptcha.py +0 -0
  150. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_retry.py +0 -0
  151. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_routes.py +0 -0
  152. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_video.py +0 -0
  153. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/__init__.py +0 -0
  154. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/test_factory.py +0 -0
  155. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/test_ui_automation.py +0 -0
  156. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/cli/__init__.py +0 -0
  157. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/cli/test_cli_image.py +0 -0
  158. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/cli/test_cli_run.py +0 -0
  159. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/cli/test_helpers.py +0 -0
  160. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/conftest.py +0 -0
  161. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/e2e/__init__.py +0 -0
  162. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/features/__init__.py +0 -0
  163. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/features/auth.feature +0 -0
  164. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/features/conftest.py +0 -0
  165. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/features/test_step_collision_guard.py +0 -0
  166. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/features/test_video_steps.py +0 -0
  167. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/features/video.feature +0 -0
  168. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/smoke/__init__.py +0 -0
  169. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/smoke/test_real_flow.py +0 -0
  170. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_auth.py +0 -0
  171. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_cli_video.py +0 -0
  172. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_config.py +0 -0
  173. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_errors.py +0 -0
  174. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_manifest.py +0 -0
  175. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_observability.py +0 -0
  176. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_paths.py +0 -0
  177. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_profile_store.py +0 -0
  178. {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_smoke.py +0 -0
@@ -28,8 +28,10 @@ LICENSE text eol=lf
28
28
  *.sh text eol=lf
29
29
  *.bash text eol=lf
30
30
 
31
- # Windows scripts MUST stay CRLF or they break under PowerShell / cmd.exe
32
- *.ps1 text eol=crlf
31
+ # PowerShell handles LF fine on both PS 5.1 and Core, so keep .ps1 as LF.
32
+ # cmd.exe has historical edge cases with multi-line batch files, so .bat/.cmd
33
+ # stay CRLF.
34
+ *.ps1 text eol=lf
33
35
  *.bat text eol=crlf
34
36
  *.cmd text eol=crlf
35
37
 
@@ -15,6 +15,7 @@ env/
15
15
 
16
16
  # Test / coverage
17
17
  .pytest_cache/
18
+ pytest-of-*/
18
19
  .coverage
19
20
  .coverage.*
20
21
  htmlcov/
@@ -7,6 +7,101 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.6.0a2] — 2026-05-16
11
+
12
+ > **Real Chrome auth strategy — G12 block resolved.** This release restores
13
+ > `gflow auth login` reliability by routing logins through the system's real
14
+ > Google Chrome instead of Playwright's bundled Chromium. A carefully ordered
15
+ > stealth configuration prevents Google's bot-detection from blocking the sign-in
16
+ > flow.
17
+
18
+ ### Added
19
+
20
+ - **`--browser [auto|chrome|internal]` flag** on `gflow auth login` — selects
21
+ the browser strategy. `chrome` uses real system Chrome (stealth). `internal`
22
+ falls back to bundled Chromium. `auto` (default) probes for real Chrome and
23
+ falls back gracefully.
24
+ - **`GFLOW_CLI_AUTH_BROWSER` env var** — overrides the browser strategy without
25
+ a CLI flag.
26
+ - **`RealChromeStrategy`** (`src/gflow_cli/auth/real_chrome.py`) — stealth
27
+ persistent context via `channel="chrome"` with
28
+ `--disable-blink-features=AutomationControlled` and a JS init-script to mask
29
+ `navigator.webdriver`.
30
+ - **`InternalChromiumStrategy`** — extracted from the previous `auth.py` monolith
31
+ as an explicit fallback strategy.
32
+ - **`AuthStrategyFactory`** — routes `auto`/`chrome`/`internal` to the
33
+ appropriate strategy based on system state.
34
+ - **`is_chrome_available()`** in `browser_manager.py` — non-raising probe for
35
+ system Chrome presence.
36
+ - **4 new BDD scenarios** in `tests/features/auth_login.feature` covering all
37
+ `--browser` modes.
38
+
39
+ ### Fixed
40
+
41
+ - **G12 bot-detection block** — Google's "browser not secure" rejection (`/v3/signin/rejected`)
42
+ is bypassed by the stealth Chrome launch configuration. Root cause: without
43
+ `--disable-blink-features=AutomationControlled`, Blink's C++ engine sets
44
+ `navigator.webdriver = true` as a non-configurable native property before any
45
+ JS init script can run, making `Object.defineProperty` overrides silently fail.
46
+ - **`add_init_script` timing** — registration now occurs before any page is
47
+ accessed, ensuring the stealth script fires on every navigation including the
48
+ first `goto()`.
49
+ - **Privacy Guard** — `RealChromeStrategy` validates that `profile_dir` is inside
50
+ `GFLOW_CLI_HOME` and raises `SecurityError` if it is not, preventing accidental
51
+ use of the user's primary system Chrome profile.
52
+ - **`ConfigurationError` on missing Chrome** — clear "Chrome binary not found"
53
+ message with install guidance when `--browser chrome` is requested but Chrome
54
+ is not on the system.
55
+ - **Two pyright `TypedDict` errors** in cookie access (`c["name"]` → `c.get("name")`).
56
+
57
+ ### Changed
58
+
59
+ - `src/gflow_cli/auth.py` promoted to `src/gflow_cli/auth/` package with
60
+ `__init__.py`, `base.py`, `factory.py`, `internal_chromium.py`,
61
+ `real_chrome.py`, `strategies.py`.
62
+ - `gflow auth login` now prints the launch strategy announcement before opening
63
+ any browser window.
64
+
65
+
66
+
67
+ > **Shell-friendly multi-prompt `t2i` + performance hardening.** This release
68
+ > promotes `gflow image t2i` to a variadic command that can consume multiple
69
+ > prompts from positional arguments, a line-delimited text file, or standard
70
+ > input. Core generation logic has been consolidated into a shared
71
+ > `image_batch` module, ensuring architectural consistency between shell runs
72
+ > and JSON-described batches. This version also ships critical resource
73
+ > cleanup fixes for SQLite connections and OOM protection for stdin streams.
74
+
75
+ ### Added
76
+
77
+ - **Variadic `gflow image t2i`** — now accepts multiple positional prompts.
78
+ Example: `gflow image t2i "prompt 1" "prompt 2"`.
79
+ - **`--prompts-file <PATH>` and `--stdin`** — read batches of prompts from
80
+ text files or pipes. All prompts in a batch share a single Flow session
81
+ and project, significantly reducing reCAPTCHA and project-init overhead.
82
+ - **Shared `image_batch` logic** (`src/gflow_cli/image_batch.py`) — unified
83
+ orchestration, validation, and rendering for all multi-prompt generation
84
+ surfaces.
85
+ - **Memory safety for stdin** — bounded read on standard input prevents
86
+ memory exhaustion when piping large or infinite streams.
87
+ - **`examples/multi_prompt_t2i.py` + `examples/sample_prompts.txt`** —
88
+ runnable template for the new shell-multi-prompt surface.
89
+
90
+ ### Fixed
91
+
92
+ - **Resource leaks in SQLite** — ensured all `sqlite3` connections are
93
+ properly closed via `try...finally` blocks, resolving resource exhaust
94
+ warnings and potential hangs in long-running processes.
95
+ - **Output directory partitioning** — `t2i` batches now correctly land in
96
+ date-partitioned folders (`images/YYYY-MM-DD/`) by default, aligning
97
+ with the core design spec.
98
+
99
+ ### Changed
100
+
101
+ - **CLI validation alignment** — `t2i` and `i2i` subcommands now use
102
+ authoritative domain constants for model, aspect, and count validation,
103
+ ensuring UI help text and defaults stay in perfect sync with the engine.
104
+
10
105
  ## [0.5.0a1] — 2026-05-12
11
106
 
12
107
  > **Pluggable image transport + JSON-described batch runs.** The image
@@ -397,9 +492,9 @@ shell-script template that branches on these codes.
397
492
 
398
493
  First skeleton. Not functional end-to-end yet.
399
494
 
400
- [Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.4.0a2...HEAD
401
- [0.4.0a2]: https://github.com/ffroliva/gflow-cli/compare/v0.4.0a1...v0.4.0a2
402
- [0.4.0a1]: https://github.com/ffroliva/gflow-cli/compare/v0.3.0a1...v0.4.0a1
495
+ [Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.6.0a1...HEAD
496
+ [0.6.0a1]: https://github.com/ffroliva/gflow-cli/compare/v0.5.0a1...v0.6.0a1
497
+ [0.5.0a1]: https://github.com/ffroliva/gflow-cli/compare/v0.4.0a2...v0.5.0a1
403
498
  [0.3.0a1]: https://github.com/ffroliva/gflow-cli/releases/tag/v0.3.0a1
404
499
  [0.2.0a1]: https://github.com/ffroliva/gflow-cli/releases/tag/v0.2.0a1
405
500
  [0.1.0]: https://github.com/ffroliva/gflow-cli/releases/tag/v0.1.0
@@ -142,3 +142,66 @@ uv run gflow auth login --profile experiments # named profile
142
142
  - [docs/INDEX.md](docs/INDEX.md) — full doc routing
143
143
  - [PLAN.md](PLAN.md) — implementation roadmap with phases & ADRs
144
144
  - [.claude/README.md](.claude/README.md) — what's in `.claude/` and how to extend it
145
+
146
+ # context-mode — MANDATORY routing rules
147
+
148
+ You have context-mode MCP tools available. These rules are NOT optional — they protect your context window from flooding. A single unrouted command can dump 56 KB into context and waste the entire session.
149
+
150
+ ## BLOCKED commands — do NOT attempt these
151
+
152
+ ### curl / wget — BLOCKED
153
+ Any Bash command containing `curl` or `wget` is intercepted and replaced with an error message. Do NOT retry.
154
+ Instead use:
155
+ - `ctx_fetch_and_index(url, source)` to fetch and index web pages
156
+ - `ctx_execute(language: "javascript", code: "const r = await fetch(...)")` to run HTTP calls in sandbox
157
+
158
+ ### Inline HTTP — BLOCKED
159
+ Any Bash command containing `fetch('http`, `requests.get(`, `requests.post(`, `http.get(`, or `http.request(` is intercepted and replaced with an error message. Do NOT retry with Bash.
160
+ Instead use:
161
+ - `ctx_execute(language, code)` to run HTTP calls in sandbox — only stdout enters context
162
+
163
+ ### WebFetch — BLOCKED
164
+ WebFetch calls are denied entirely. The URL is extracted and you are told to use `ctx_fetch_and_index` instead.
165
+ Instead use:
166
+ - `ctx_fetch_and_index(url, source)` then `ctx_search(queries)` to query the indexed content
167
+
168
+ ## REDIRECTED tools — use sandbox equivalents
169
+
170
+ ### Bash (>20 lines output)
171
+ Bash is ONLY for: `git`, `mkdir`, `rm`, `mv`, `cd`, `ls`, `npm install`, `pip install`, and other short-output commands.
172
+ For everything else, use:
173
+ - `ctx_batch_execute(commands, queries)` — run multiple commands + search in ONE call
174
+ - `ctx_execute(language: "shell", code: "...")` — run in sandbox, only stdout enters context
175
+
176
+ ### Read (for analysis)
177
+ If you are reading a file to **Edit** it → Read is correct (Edit needs content in context).
178
+ If you are reading to **analyze, explore, or summarize** → use `ctx_execute_file(path, language, code)` instead. Only your printed summary enters context. The raw file content stays in the sandbox.
179
+
180
+ ### Grep (large results)
181
+ Grep results can flood context. Use `ctx_execute(language: "shell", code: "grep ...")` to run searches in sandbox. Only your printed summary enters context.
182
+
183
+ ## Tool selection hierarchy
184
+
185
+ 1. **GATHER**: `ctx_batch_execute(commands, queries)` — Primary tool. Runs all commands, auto-indexes output, returns search results. ONE call replaces 30+ individual calls.
186
+ 2. **FOLLOW-UP**: `ctx_search(queries: ["q1", "q2", ...])` — Query indexed content. Pass ALL questions as array in ONE call.
187
+ 3. **PROCESSING**: `ctx_execute(language, code)` | `ctx_execute_file(path, language, code)` — Sandbox execution. Only stdout enters context.
188
+ 4. **WEB**: `ctx_fetch_and_index(url, source)` then `ctx_search(queries)` — Fetch, chunk, index, query. Raw HTML never enters context.
189
+ 5. **INDEX**: `ctx_index(content, source)` — Store content in FTS5 knowledge base for later search.
190
+
191
+ ## Subagent routing
192
+
193
+ When spawning subagents (Agent/Task tool), the routing block is automatically injected into their prompt. Bash-type subagents are upgraded to general-purpose so they have access to MCP tools. You do NOT need to manually instruct subagents about context-mode.
194
+
195
+ ## Output constraints
196
+
197
+ - Keep responses under 500 words.
198
+ - Write artifacts (code, configs, PRDs) to FILES — never return them as inline text. Return only: file path + 1-line description.
199
+ - When indexing content, use descriptive source labels so others can `ctx_search(source: "label")` later.
200
+
201
+ ## ctx commands
202
+
203
+ | Command | Action |
204
+ |---------|--------|
205
+ | `ctx stats` | Call the `ctx_stats` MCP tool and display the full output verbatim |
206
+ | `ctx doctor` | Call the `ctx_doctor` MCP tool, run the returned shell command, display as checklist |
207
+ | `ctx upgrade` | Call the `ctx_upgrade` MCP tool, run the returned shell command, display as checklist |
@@ -133,6 +133,35 @@ _(none yet)_
133
133
 
134
134
  ## Resolved
135
135
 
136
+ ### G12 "browser not secure" block — Google rejects automated sign-in
137
+
138
+ - **Status:** Resolved · **Severity:** Critical (blocked `gflow auth login`) · **Fixed in:** v0.6.0a2
139
+
140
+ Google's sign-in flow (`accounts.google.com/v3/signin/rejected`) detected Playwright's bundled Chromium as an automated browser and refused the login with no user-facing error.
141
+
142
+ **Root cause (timing race):** Without `--disable-blink-features=AutomationControlled`,
143
+ Blink's C++ engine sets `navigator.webdriver = true` as a non-configurable, non-writable
144
+ native property at Chrome startup — before any JavaScript (including `add_init_script`)
145
+ can run. The `Object.defineProperty` override silently fails. With the flag, the property
146
+ is never set; the JS override then works as belt-and-suspenders.
147
+
148
+ **Resolution:** `v0.6.0a2` adds `RealChromeStrategy` — a new auth strategy that launches
149
+ the system's real Google Chrome via Playwright's `channel="chrome"` with stealth flags.
150
+
151
+ ```bash
152
+ # Bypass G12 block explicitly:
153
+ gflow auth login --browser chrome
154
+
155
+ # Or rely on auto-detection (default behaviour; picks real Chrome if installed):
156
+ gflow auth login
157
+ ```
158
+
159
+ A cosmetic "You are using an unsupported command-line flag" notice may appear briefly in
160
+ the Chrome window — this is harmless and can be dismissed. It is the accepted trade-off
161
+ for bypassing G12.
162
+
163
+ ---
164
+
136
165
  ### v0.1 — provider methods are stubs
137
166
 
138
167
  - **Status:** Resolved · **Severity:** Critical (blocked usage) · **Fixed in:** v0.2.0a1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gflow-cli
3
- Version: 0.5.0a1
3
+ Version: 0.6.0a2
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
@@ -125,6 +125,7 @@ Read the full [DISCLAIMER](DISCLAIMER.md) before deploying this in any productio
125
125
  | Pluggable image transport + `ui_automation` default strategy | ✅ done (v0.5.0a1) |
126
126
  | `gflow run --config <file>` sequential JSON batches | ✅ done (v0.5.0a1) |
127
127
  | `examples/` directory with runnable single-image + batch scripts | ✅ done (v0.5.0a1) |
128
+ | Shell multi-prompt `gflow image t2i` (`PROMPT...`, `--prompts-file`, `--stdin`) | ✅ done (v0.6.0a1) |
128
129
  | Provider abstraction for official Veo 3.1 API | ⏳ planned (v0.6+) |
129
130
 
130
131
  ### What's new in v0.5.0a1
@@ -136,6 +137,24 @@ Read the full [DISCLAIMER](DISCLAIMER.md) before deploying this in any productio
136
137
 
137
138
  ---
138
139
 
140
+ ## Demo
141
+
142
+ ![gflow image t2i — single 9:16 prompt, streaming structlog output, PNG on disk](docs/assets/example-run.gif)
143
+
144
+ *A single `gflow image t2i "..." --aspect 9:16 --model nano2 --out ...` call against a logged-in Pro/Ultra profile. The terminal shows the streaming `structlog` JSON for the run, the final `ls` of the written PNG, and nothing else — Chromium drives the Flow editor silently in the background because the persistent Playwright session is already warm, so this take is intentionally terminal-only.*
145
+
146
+ **Try it yourself** — this is the exact command the GIF runs:
147
+
148
+ ```bash
149
+ gflow image t2i "a quiet mountain lake at dawn, cinematic photography" --aspect 9:16 --model nano2 --out ./gflow-output/example-single
150
+ ```
151
+
152
+ One prompt, default model (`nano2` = Nano Banana 2), 9:16 portrait, written as `./gflow-output/example-single/<media_name>_0.png`. Wall time is typically 30–90s on a warm profile; the first call after a fresh `gflow auth login` is slower because Playwright spins up Chromium and navigates to the Flow editor. See [`docs/USAGE.md`](docs/USAGE.md) for the full `gflow image t2i` flag reference (`--model`, `--aspect`, `-n`, `--seed`, `--profile`, `--transport`).
153
+
154
+ To reproduce the recording yourself, see [`scripts/record_demo.ps1`](scripts/record_demo.ps1) (Windows, requires OBS + ffmpeg + gifski).
155
+
156
+ ---
157
+
139
158
  ## Prerequisites
140
159
 
141
160
  | Requirement | Why |
@@ -243,7 +262,9 @@ gflow auth login # one-time browser sign
243
262
  gflow auth status # show current session
244
263
 
245
264
  gflow image upload <path> # upload PNG/JPEG → asset UUID
246
- gflow image t2i "<prompt>" [--model] [--aspect] [-n] # text-to-image (1–4 per call)
265
+ gflow image t2i "<prompt>" [...] [--model] [--aspect] # text-to-image; repeat prompts for a warm batch
266
+ gflow image t2i --prompts-file prompts.txt # text-file multi-prompt batch
267
+ gflow image t2i --stdin # stdin multi-prompt batch
247
268
  gflow image i2i "<prompt>" --ref PATH_OR_UUID [...] # image-to-image (1–4 per call)
248
269
 
249
270
  gflow video t2v "<prompt>" -o out.mp4 # text-to-video (Veo 3.1)
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **Status:** Living document. Updated as phases complete.
4
4
  > **Owner:** [@ffroliva](https://github.com/ffroliva)
5
- > **Last revised:** 2026-05-11 (Phase 4 Hardening shipped, v0.4.0a2)
5
+ > **Last revised:** 2026-05-15 (Phase 6 / v0.6.0a2 — Real Chrome auth)
6
6
 
7
7
  This plan turns the v0.1 scaffold into a production-grade CLI for Google AI Ultra/Pro subscribers who want to spend their Flow credits via batch automation. The plan is opinionated, treating this repo as a portfolio-grade benchmark.
8
8
 
@@ -76,7 +76,12 @@ Current package layout (post-Phase 4):
76
76
  src/gflow_cli/
77
77
  ├── __init__.py
78
78
  ├── __main__.py
79
- ├── auth.py login + status (Playwright headed for login)
79
+ ├── auth/ v0.6.0a2: strategy pattern (real Chrome + internal Chromium)
80
+ │ ├── __init__.py ← login(), AuthStatus, get_status(), list_profiles()
81
+ │ ├── base.py ← AuthStrategy Protocol
82
+ │ ├── factory.py ← AuthStrategyFactory (auto/chrome/internal routing)
83
+ │ ├── internal_chromium.py ← bundled Chromium (legacy fallback)
84
+ │ └── real_chrome.py ← system Chrome with G12 stealth flags
80
85
  ├── cli.py ← Click app, top-level + auth subgroup
81
86
  ├── cli_image.py ← gflow image upload/t2i/i2i (Click subgroup)
82
87
  ├── cli_video.py ← gflow video t2v/i2v/batch (Click subgroup)
@@ -323,17 +328,28 @@ Page creation averaged **44.7–48.1 ms per page** across N=2/4/8/16 inside one
323
328
 
324
329
  ### Phase 5 — Public alpha soak + first non-alpha release
325
330
 
326
- `v0.2.0a1` through `v0.4.0a2` are already on PyPI under Trusted Publishing.
331
+ `v0.2.0a1` through `v0.6.0a1` are already on PyPI under Trusted Publishing.
327
332
  Phase 5 is the soak window before dropping the `aN` suffix:
328
333
 
329
- - Let `v0.4.0a2` soak on PyPI for at least 1 week with external installs
330
- - Verify `uvx --from "gflow-cli==0.4.0a2" gflow --help` works on a fresh machine on all three OSes (Windows / macOS / Linux)
334
+ - Let `v0.6.0a1` soak on PyPI for at least 1 week with external installs
335
+ - Verify `uvx --from "gflow-cli==0.6.0a1" gflow --help` works on a fresh machine on all three OSes (Windows / macOS / Linux)
331
336
  - Triage any issues filed by external users (`gh issue list`)
332
- - Tag the first non-alpha (`v0.4.0`) once the surface is stable enough for external automation
337
+ - Tag the first non-alpha (`v0.6.0`) once the surface is stable enough for external automation
333
338
  - Optional follow-up: scaffold `OfficialVeoProvider` against [`googleapis/python-genai`](https://github.com/googleapis/python-genai) behind `GFLOW_CLI_PROVIDER=official`
334
339
 
335
340
  ---
336
341
 
342
+ ### Technical Debt & Refactoring — BACKLOG
343
+
344
+ Identified during v0.6.0a1 Council Review. To be addressed before or during Phase 6.
345
+
346
+ - **Unify Output Resolution**: `cli_run.py` uses `out/<UTC>` while `cli_image.py` uses `images/<YYYY-MM-DD>`. Align both to the date-partitioned daily strategy or a single shared helper.
347
+ - **Deduplicate JSON Validation**: `cli_run.py` duplicates model/aspect validation logic. Consolidate into `image_batch.py` helpers.
348
+ - **Generic Batch Orchestrator**: Refactor `run_image_batch` to accept a worker callback. This will allow the same sequential/fail-fast orchestration to support `video` batches in the future.
349
+ - **Playwright Thread Safety**: Investigate why `unittest.mock.patch` plus multi-threaded `asyncio` hangs in `tests/test_browser_manager.py`. The test is currently skipped.
350
+
351
+ ---
352
+
337
353
  ### Phase 6 — Operations history & cost tracking — BACKLOG
338
354
 
339
355
  Foundation laid by Phase 4's structured `error_raised` events + Problem Details. Phase 6 adds a local persistence layer so users can answer "what did I generate last week and what did it cost?".
@@ -71,6 +71,7 @@ Read the full [DISCLAIMER](DISCLAIMER.md) before deploying this in any productio
71
71
  | Pluggable image transport + `ui_automation` default strategy | ✅ done (v0.5.0a1) |
72
72
  | `gflow run --config <file>` sequential JSON batches | ✅ done (v0.5.0a1) |
73
73
  | `examples/` directory with runnable single-image + batch scripts | ✅ done (v0.5.0a1) |
74
+ | Shell multi-prompt `gflow image t2i` (`PROMPT...`, `--prompts-file`, `--stdin`) | ✅ done (v0.6.0a1) |
74
75
  | Provider abstraction for official Veo 3.1 API | ⏳ planned (v0.6+) |
75
76
 
76
77
  ### What's new in v0.5.0a1
@@ -82,6 +83,24 @@ Read the full [DISCLAIMER](DISCLAIMER.md) before deploying this in any productio
82
83
 
83
84
  ---
84
85
 
86
+ ## Demo
87
+
88
+ ![gflow image t2i — single 9:16 prompt, streaming structlog output, PNG on disk](docs/assets/example-run.gif)
89
+
90
+ *A single `gflow image t2i "..." --aspect 9:16 --model nano2 --out ...` call against a logged-in Pro/Ultra profile. The terminal shows the streaming `structlog` JSON for the run, the final `ls` of the written PNG, and nothing else — Chromium drives the Flow editor silently in the background because the persistent Playwright session is already warm, so this take is intentionally terminal-only.*
91
+
92
+ **Try it yourself** — this is the exact command the GIF runs:
93
+
94
+ ```bash
95
+ gflow image t2i "a quiet mountain lake at dawn, cinematic photography" --aspect 9:16 --model nano2 --out ./gflow-output/example-single
96
+ ```
97
+
98
+ One prompt, default model (`nano2` = Nano Banana 2), 9:16 portrait, written as `./gflow-output/example-single/<media_name>_0.png`. Wall time is typically 30–90s on a warm profile; the first call after a fresh `gflow auth login` is slower because Playwright spins up Chromium and navigates to the Flow editor. See [`docs/USAGE.md`](docs/USAGE.md) for the full `gflow image t2i` flag reference (`--model`, `--aspect`, `-n`, `--seed`, `--profile`, `--transport`).
99
+
100
+ To reproduce the recording yourself, see [`scripts/record_demo.ps1`](scripts/record_demo.ps1) (Windows, requires OBS + ffmpeg + gifski).
101
+
102
+ ---
103
+
85
104
  ## Prerequisites
86
105
 
87
106
  | Requirement | Why |
@@ -189,7 +208,9 @@ gflow auth login # one-time browser sign
189
208
  gflow auth status # show current session
190
209
 
191
210
  gflow image upload <path> # upload PNG/JPEG → asset UUID
192
- gflow image t2i "<prompt>" [--model] [--aspect] [-n] # text-to-image (1–4 per call)
211
+ gflow image t2i "<prompt>" [...] [--model] [--aspect] # text-to-image; repeat prompts for a warm batch
212
+ gflow image t2i --prompts-file prompts.txt # text-file multi-prompt batch
213
+ gflow image t2i --stdin # stdin multi-prompt batch
193
214
  gflow image i2i "<prompt>" --ref PATH_OR_UUID [...] # image-to-image (1–4 per call)
194
215
 
195
216
  gflow video t2v "<prompt>" -o out.mp4 # text-to-video (Veo 3.1)
@@ -57,6 +57,43 @@ The hexagonal target above is the steady state. The **current** package — and
57
57
  - Restructure existing modules beyond minimal dedup (shared CLI helpers were promoted to `gflow_cli._cli_helpers` at the package top level — kept flat to avoid a `cli.py` file / `cli/` package collision).
58
58
  - Introduce dependency-injection containers, command/query buses, or any DDD/CQRS scaffolding (deferred per [PLAN ADR #2](../PLAN.md#5-decision-log-adrs-in-miniature)).
59
59
 
60
+ **v0.6.0a2 module additions — auth strategy package:**
61
+
62
+ `auth.py` was promoted to a sub-package `gflow_cli.auth/` with the strategy pattern to support multiple browser backends for the `gflow auth login` command:
63
+
64
+ ```text
65
+ src/gflow_cli/auth/
66
+ ├── __init__.py # public: login(), AuthStatus, get_status(), list_profiles()
67
+ ├── base.py # AuthStrategy Protocol — the shared contract
68
+ ├── factory.py # AuthStrategyFactory — routes auto/chrome/internal modes
69
+ ├── internal_chromium.py # InternalChromiumStrategy — Playwright bundled Chromium (legacy)
70
+ ├── real_chrome.py # RealChromeStrategy — system Google Chrome with stealth flags
71
+ └── strategies.py # (internal) shared Playwright helpers
72
+ ```
73
+
74
+ **Why:** Google's bot-detection ("G12 block") rejects Playwright's bundled Chromium during `gflow auth login`. Launching the user's installed Google Chrome with `--disable-blink-features=AutomationControlled` plus a JS `add_init_script` that overrides `navigator.webdriver` bypasses detection. Two strategies are needed because the setup (persistent-context flags, Chrome binary path, stealth init) differs fundamentally between them.
75
+
76
+ **AuthStrategy Protocol** (`base.py`):
77
+ ```python
78
+ class AuthStrategy(Protocol):
79
+ name: str
80
+ async def login(self, profile_dir: Path, headless: bool) -> None: ...
81
+ ```
82
+
83
+ **AuthStrategyFactory** (`factory.py`):
84
+ - `mode="auto"` — probes `is_chrome_available()` → `RealChromeStrategy` if found, else `InternalChromiumStrategy` with a warning.
85
+ - `mode="chrome"` — explicit `RealChromeStrategy`; raises `ConfigurationError` if Chrome binary missing.
86
+ - `mode="internal"` — explicit `InternalChromiumStrategy`.
87
+
88
+ **RealChromeStrategy stealth design** (`real_chrome.py`):
89
+ - Uses a **Passive Capture** pattern: launches system Chrome via `subprocess.Popen` without any automation flags or remote-debugging ports.
90
+ - Provides a 100% clean browser process that Google's G12 block cannot detect.
91
+ - The CLI blocks on `proc.wait()`, prompting the user to complete the sign-in and **close the browser completely**.
92
+ - Post-close: performs a fast, headless `launch_persistent_context` probe to verify the `SAPISID` cookie was successfully captured.
93
+ - Privacy guard: raises `SecurityError` if the resolved `profile_dir` is outside `GFLOW_CLI_HOME` — protects the user's primary system Chrome profile from being used as a session store.
94
+
95
+ **CLI surface:** `gflow auth login [--browser auto|chrome|internal]` (env: `GFLOW_CLI_AUTH_BROWSER`).
96
+
60
97
  When the project converges on the hexagonal target above, modules graduate to layers: e.g., today's `gflow_cli.api` becomes `gflow_cli.infrastructure.flow_api`, `gflow_cli.cli` becomes `gflow_cli.interfaces.cli`, and so on. The modular-monolith shape is the staging area, not the destination.
61
98
 
62
99
  ## Folder layout
@@ -64,7 +101,7 @@ When the project converges on the hexagonal target above, modules graduate to la
64
101
  > **Note: this document describes the TARGET architecture, not the current
65
102
  > package layout.** The current shape (per [PLAN.md § 2](../PLAN.md#2-architecture-steady-state)
66
103
  > and [ADR #2](../PLAN.md#5-decision-log-adrs-in-miniature)) is the simpler
67
- > `src/gflow_cli/{api/, cli.py, cli_image.py, cli_video.py, auth.py,
104
+ > `src/gflow_cli/{api/, auth/, cli.py, cli_image.py, cli_video.py,
68
105
  > config.py, paths.py, profile_store.py}`. The DDD layout below was deferred
69
106
  > indefinitely; converge toward it incrementally if/when a second `Provider`
70
107
  > or a `gflow serve` HTTP front-end justifies the split.
@@ -127,14 +127,38 @@ Use `gflow auth login --profile <name>` to add or refresh a profile.
127
127
 
128
128
  ### `gflow auth login`
129
129
 
130
- Opens a headed Chromium, navigates to `https://labs.google/fx/tools/flow?hl=en`, and waits for you to sign in. The browser window must be closed within **10 minutes total** (the underlying `wait_for_event("close", timeout=600_000)`); after that the command times out. When the window is closed, the captured session is persisted to disk.
130
+ Opens a headed browser, navigates to `https://labs.google/fx/tools/flow?hl=en`, and waits
131
+ for you to sign in. The CLI automatically detects success and persists the session to disk.
131
132
 
132
133
  ```bash
133
- gflow auth login # default profile
134
- gflow auth login --profile work # named profile (creates if missing)
134
+ gflow auth login # default profile, auto browser
135
+ gflow auth login --profile work # named profile (creates if missing)
136
+ gflow auth login --browser chrome # force real Chrome (bypasses G12 block)
135
137
  ```
136
138
 
137
- Re-running this command refreshes an expired session: it reuses the existing profile dir, so you typically just have to click "Continue as <you>" on the Google account chooser.
139
+ Re-running this command refreshes an expired session: it reuses the existing profile dir,
140
+ so you typically just have to click "Continue as <you>" on the Google account chooser.
141
+
142
+ #### `--browser [auto|chrome|internal]`
143
+
144
+ | Value | Browser used | When to use |
145
+ |---|---|---|
146
+ | `auto` (default) | Real Chrome if installed; falls back to internal | First choice for most users |
147
+ | `chrome` | System Google Chrome (**Passive Capture**) | Required to bypass "G12" blocks |
148
+ | `internal` | Playwright's bundled Chromium | Fallback when Chrome isn't installed |
149
+
150
+ Override with the env var: `GFLOW_CLI_AUTH_BROWSER=chrome gflow auth login`
151
+
152
+ **Why `chrome` bypasses bot detection:** Playwright's default automation mode exposes
153
+ `navigator.webdriver = true` as a non-configurable native property. Google detects this
154
+ and redirects to `/v3/signin/rejected` (the "G12 block"). The `chrome` strategy
155
+ implements **Passive Capture**: it launches your real system Chrome as a 100% standard
156
+ process without any automation flags or debugging ports. You log in manually, close
157
+ the window, and `gflow` extracts the verified session from the profile.
158
+
159
+ **Privacy guard:** The `chrome` strategy strictly refuses to use any profile directory
160
+ outside `GFLOW_CLI_HOME`. This protects your primary system Chrome profile from
161
+ accidental interference or data corruption.
138
162
 
139
163
  ### `gflow auth status`
140
164
 
@@ -82,15 +82,24 @@ gflow image i2i "make it cinematic" --ref "$UUID"
82
82
 
83
83
  ## `gflow image t2i`
84
84
 
85
- Generate 1–4 images from a text prompt using Google Flow's Imagen / Nano Banana models.
85
+ Generate 1–4 images from one text prompt, or run a shell-friendly batch of 1–50
86
+ prompts through one Flow session/project.
86
87
 
87
88
  ```text
88
- gflow image t2i PROMPT [OPTIONS]
89
+ gflow image t2i PROMPT [PROMPT ...] [OPTIONS]
90
+ gflow image t2i --prompts-file FILE [OPTIONS]
91
+ gflow image t2i --stdin [OPTIONS]
89
92
 
90
93
  Arguments:
91
- PROMPT Text prompt. [required]
94
+ PROMPT Text prompt. Repeat for multi-prompt mode.
92
95
 
93
96
  Options:
97
+ --prompts-file FILE UTF-8 text file: one prompt per non-empty line;
98
+ whole-line # comments skipped.
99
+ --stdin Read prompts from stdin using the same format.
100
+ --continue-on-error /
101
+ --fail-fast Continue after per-prompt failures or stop at the
102
+ first failed prompt. [default: continue-on-error]
94
103
  --model [nano2|nano-pro|image4]
95
104
  Image model alias. [default: nano2]
96
105
  --aspect [9:16|16:9|1:1|4:3|3:4]
@@ -109,12 +118,26 @@ Options:
109
118
  | `nano-pro` | Nano Banana Pro (`GEM_PIX_2`) | Higher quality, slower. |
110
119
  | `image4` | Imagen 4 (`IMAGEN_3_5`) | Photoreal-leaning Imagen variant. |
111
120
 
112
- **Seed-requires-count==1 invariant.** `--seed` is only valid when generating a single image (`-n 1`). For multi-image runs the CLI rejects the combination upfront — multi-image fan-out uses N independent random seeds (one per shot) wired to a shared `batch_id`, which gives you variation. If you need reproducibility across many shots, run `--seed` once per call in a loop.
121
+ **Multi-prompt shortcut.**
122
+
123
+ - Positional multi-prompt: `gflow image t2i "p1" "p2" "p3"`.
124
+ - `--prompts-file FILE`: UTF-8 text, one prompt per non-empty line, whole-line
125
+ `#` comments skipped.
126
+ - `--stdin`: same format as `--prompts-file`.
127
+ - Sources are mutually exclusive.
128
+ - Output names use `prompt_<prompt-index>_<variation-index>.png`.
129
+ - With `-n 4`, each prompt produces four images; the maximum shell shortcut
130
+ fan-out is 50 prompts * 4 = 200 images.
131
+ - `--continue-on-error` is default; `--fail-fast` stops after the first failed
132
+ prompt.
133
+
134
+ **Seed-requires-count==1 invariant.** `--seed` is only valid when generating a single image (`-n 1`). For multi-image runs the CLI rejects the combination upfront — multi-image fan-out uses N independent random seeds (one per shot) wired to a shared `batch_id`, which gives you variation. `--seed` is not supported in multi-prompt mode; use separate single-prompt commands for seeded work today.
113
135
 
114
136
  **Output paths.**
115
137
 
116
138
  - **Default (`--out` omitted).** Files land under `$GFLOW_CLI_OUTPUT_DIR/images/<YYYY-MM-DD>/<media_name>_<n>.png`. The date partition keeps long-running batches navigable.
117
139
  - **`--out DIR` provided.** Files are written **flat** as `<DIR>/<media_name>_<n>.png` — no date subdirectory. `--out` must be a directory; flat-file output paths are not supported (you can rename after the fact).
140
+ - **Multi-prompt mode.** Files are written as `prompt_<prompt-index>_<variation-index>.png`; the prompt index and variation index are zero-based.
118
141
 
119
142
  **Examples:**
120
143
 
@@ -130,6 +153,15 @@ gflow image t2i "variations of a minimalist fox logo" -n 4 --aspect 1:1 --out ./
130
153
 
131
154
  # Reproducible single shot
132
155
  gflow image t2i "reproducible reference shot" --seed 42
156
+
157
+ # Three prompts in one warm Flow session/project
158
+ gflow image t2i "p1" "p2" "p3" --aspect 16:9 --model image4
159
+
160
+ # Text file input: comments and blank lines are ignored
161
+ gflow image t2i --prompts-file prompts.txt --fail-fast
162
+
163
+ # Pipeline input
164
+ Get-Content prompts.txt | gflow image t2i --stdin
133
165
  ```
134
166
 
135
167
  A 4-image run with `--out ./logos/` produces: