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.
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/.gitattributes +4 -2
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/.gitignore +1 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/CHANGELOG.md +98 -3
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/CLAUDE.md +63 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/KNOWN_ISSUES.md +29 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/PKG-INFO +23 -2
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/PLAN.md +22 -6
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/README.md +22 -1
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/ARCHITECTURE.md +38 -1
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/AUTHENTICATION.md +28 -4
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/USAGE.md +36 -4
- gflow_cli-0.6.0a2/docs/assets/example-run.gif +0 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/2026-05-14-shell-multi-prompt-orchestration.md +165 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_FINAL_ARCH.md +34 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_FINAL_SEC_UX.md +47 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_CODE.md +46 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_GEMINI.md +89 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_SECURITY.md +70 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/IMPLEMENTATION_REVIEW_PYTHON.md +37 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/IMPLEMENTATION_REVIEW_SECURITY.md +33 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN.md +1919 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_CODE.md +70 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_FOLLOWUP.md +36 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_PLANNER.md +66 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_SECURITY.md +70 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_SECURITY_FOLLOWUP.md +30 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/COUNCIL_FINAL_SEC_UX_VERIFIED.md +30 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/COUNCIL_REVIEW_PLAN_SECURITY.md +57 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/COUNCIL_REVIEW_SPEC_SECURITY.md +37 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/PLAN.md +69 -0
- gflow_cli-0.6.0a2/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/orchestration.md +20 -0
- gflow_cli-0.6.0a2/docs/superpowers/specs/2026-05-14-shell-multi-prompt-design.md +497 -0
- gflow_cli-0.6.0a2/docs/superpowers/specs/2026-05-15-auth-login-real-chrome-design.md +45 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/examples/README.md +11 -1
- gflow_cli-0.6.0a2/examples/multi_prompt_t2i.py +126 -0
- gflow_cli-0.6.0a2/examples/sample_prompts.txt +4 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/pyproject.toml +1 -1
- gflow_cli-0.6.0a2/scripts/record_demo.ps1 +226 -0
- gflow_cli-0.6.0a2/scripts/verify_chrome_auth_viability.py +209 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/__init__.py +1 -1
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/_cli_helpers.py +31 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/_common.py +7 -18
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/_fingerprint.py +4 -12
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/base.py +1 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/experimental/__init__.py +1 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/experimental/bearer.py +6 -13
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/experimental/evaluate_fetch.py +3 -8
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/experimental/sapisidhash.py +9 -13
- gflow_cli-0.5.0a1/src/gflow_cli/auth.py → gflow_cli-0.6.0a2/src/gflow_cli/auth/__init__.py +16 -34
- gflow_cli-0.6.0a2/src/gflow_cli/auth/base.py +30 -0
- gflow_cli-0.6.0a2/src/gflow_cli/auth/factory.py +52 -0
- gflow_cli-0.6.0a2/src/gflow_cli/auth/internal_chromium.py +96 -0
- gflow_cli-0.6.0a2/src/gflow_cli/auth/real_chrome.py +172 -0
- gflow_cli-0.6.0a2/src/gflow_cli/auth/strategies.py +10 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/browser_manager.py +9 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/cli.py +40 -2
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/cli_image.py +192 -33
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/cli_run.py +57 -172
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/cli_video.py +2 -1
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/errors.py +28 -0
- gflow_cli-0.6.0a2/src/gflow_cli/image_batch.py +360 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_client.py +2 -6
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_client_image.py +9 -27
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/test_base.py +1 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/test_bearer.py +1 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/test_common.py +3 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/test_evaluate_fetch.py +23 -24
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/test_fingerprint.py +1 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/test_sapisidhash.py +37 -52
- gflow_cli-0.6.0a2/tests/auth/strategies/test_factory.py +60 -0
- gflow_cli-0.6.0a2/tests/auth/strategies/test_strategies.py +243 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/cli/test_error_handling.py +59 -0
- gflow_cli-0.6.0a2/tests/cli/test_t2i_multi_prompt.py +410 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/e2e/test_transports_e2e.py +2 -6
- gflow_cli-0.6.0a2/tests/features/auth_login.feature +31 -0
- gflow_cli-0.6.0a2/tests/features/image.feature +56 -0
- gflow_cli-0.6.0a2/tests/features/test_auth_login_steps.py +127 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/features/test_auth_steps.py +3 -1
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/features/test_image_steps.py +112 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_browser_manager.py +8 -10
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/uv.lock +1 -1
- gflow_cli-0.5.0a1/tests/features/image.feature +0 -25
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/.claude/README.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/.claude/commands/release.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/.env.template +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/.github/workflows/ci.yml +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/.github/workflows/release.yml +0 -0
- {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
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/CONFIGURATION.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/CONTRIBUTING.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/DISCLAIMER.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/LICENSE +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/RELEASE.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/CONFIGURATION.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/INDEX.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/SECURITY.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/USER_GUIDE.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/superpowers/plans/2026-05-09-image-mvp-orchestration.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/superpowers/plans/2026-05-09-image-mvp.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/superpowers/plans/2026-05-09-video-mvp-orchestration.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/superpowers/plans/2026-05-09-video-mvp.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/superpowers/plans/2026-05-10-phase-4-hardening-orchestration.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/superpowers/plans/2026-05-10-phase-4-hardening.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/superpowers/specs/2026-05-10-phase-4-hardening-design.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/docs/superpowers/verifications/2026-05-11-phase-4-stage-g.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/examples/batch_from_config.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/examples/sample_config.json +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/examples/single_image_t2i.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/samples/README.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/samples/captured/01_upload_image.json +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/samples/captured/02_batchAsyncGenerateVideoText.json +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/samples/captured/04_archive_workflow.json +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/samples/captured/05_createProject.json +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/samples/captured/06_batchGenerateImages.json +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/samples/captured/07_batchGenerateImages_seeded.json +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/scripts/diag_capture_flow_traffic.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/scripts/diag_recaptcha_mint.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/scripts/smoke_e2e.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/scripts/smoke_image.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/scripts/smoke_real_chrome_image.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/scripts/smoke_worker_style.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/skills/README.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/skills/gflow-cli/SKILL.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/__main__.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/__init__.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/_retry.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/client.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/dto.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/image.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/recaptcha.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/routes.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/__init__.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/transports/ui_automation.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/api/video.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/config.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/manifest.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/observability.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/paths.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/src/gflow_cli/profile_store.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tasks/lessons.md +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/__init__.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/__init__.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_client_generate_video.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_concurrency.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_dto.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_image.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_image_dto.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_recaptcha.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_retry.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_routes.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/test_video.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/__init__.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/test_factory.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/api/transports/test_ui_automation.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/cli/__init__.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/cli/test_cli_image.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/cli/test_cli_run.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/cli/test_helpers.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/conftest.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/e2e/__init__.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/features/__init__.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/features/auth.feature +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/features/conftest.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/features/test_step_collision_guard.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/features/test_video_steps.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/features/video.feature +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/smoke/__init__.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/smoke/test_real_flow.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_auth.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_cli_video.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_config.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_errors.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_manifest.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_observability.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_paths.py +0 -0
- {gflow_cli-0.5.0a1 → gflow_cli-0.6.0a2}/tests/test_profile_store.py +0 -0
- {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
|
-
#
|
|
32
|
-
|
|
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
|
|
|
@@ -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.
|
|
401
|
-
[0.
|
|
402
|
-
[0.
|
|
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.
|
|
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
|
+

|
|
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]
|
|
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-
|
|
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
|
|
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.
|
|
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.
|
|
330
|
-
- Verify `uvx --from "gflow-cli==0.
|
|
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.
|
|
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
|
+

|
|
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]
|
|
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,
|
|
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
|
|
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
|
|
134
|
-
gflow auth login --profile work
|
|
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,
|
|
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
|
|
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.
|
|
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
|
-
**
|
|
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:
|
|
Binary file
|