gflow-cli 0.15.0__tar.gz → 0.16.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/AGENTS.md +3 -1
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/CHANGELOG.md +28 -1
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/KNOWN_ISSUES.md +31 -1
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/PKG-INFO +9 -9
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/README.md +8 -8
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/CHARACTER.md +2 -1
- gflow_cli-0.16.0/docs/IMAGE_UPSCALE_RECON.md +115 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/INDEX.md +7 -1
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/MOVIE.md +7 -4
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/USAGE.md +38 -0
- gflow_cli-0.16.0/docs/superpowers/plans/2026-06-11-image-upscale/PLAN.md +206 -0
- gflow_cli-0.16.0/docs/superpowers/plans/2026-06-11-image-upscale/SCENARIO.md +79 -0
- gflow_cli-0.16.0/docs/superpowers/plans/2026-06-11-issue-170-locale-selectors/PLAN.md +218 -0
- gflow_cli-0.16.0/docs/superpowers/plans/2026-06-11-issue-170-locale-selectors/SCENARIO.md +101 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/pyproject.toml +1 -1
- gflow_cli-0.16.0/scripts/dev/spike_image_upscale_capture.py +382 -0
- gflow_cli-0.16.0/scripts/dev/spike_image_upscale_drive.py +383 -0
- gflow_cli-0.16.0/scripts/dev/spike_image_upscale_recaptcha_action.py +188 -0
- gflow_cli-0.16.0/scripts/dev/spike_image_upscale_rest_probe.py +277 -0
- gflow_cli-0.16.0/scripts/dev/spike_issue170_picker_locale_recon.py +234 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/spike_movie_attach_payload.py +13 -1
- gflow_cli-0.16.0/scripts/diag/README.md +29 -0
- gflow_cli-0.15.0/scripts/diag_capture_flow_traffic.py → gflow_cli-0.16.0/scripts/diag/capture_flow_traffic.py +1 -1
- gflow_cli-0.16.0/scripts/diag/memory_profile.py +235 -0
- gflow_cli-0.15.0/scripts/diag_recaptcha_mint.py → gflow_cli-0.16.0/scripts/diag/recaptcha_mint.py +1 -1
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/__init__.py +1 -1
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/client.py +138 -1
- gflow_cli-0.16.0/src/gflow_cli/api/image_upscale.py +159 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/routes.py +4 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/ui_automation.py +92 -3
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/ui_automation_video.py +115 -18
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli_image.py +176 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/errors.py +31 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/exceptions.py +1 -0
- gflow_cli-0.16.0/tests/api/test_client_launch_kwargs.py +77 -0
- gflow_cli-0.16.0/tests/api/test_client_upscale.py +169 -0
- gflow_cli-0.16.0/tests/api/test_image_upscale.py +153 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_ui_automation.py +143 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_ui_automation_video.py +184 -13
- gflow_cli-0.16.0/tests/cli/test_cli_image_upscale.py +140 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/dev/test_recording_client.py +4 -1
- gflow_cli-0.16.0/tests/features/image_upscale.feature +29 -0
- gflow_cli-0.16.0/tests/features/locale_picker_include.feature +25 -0
- gflow_cli-0.16.0/tests/features/test_image_upscale_steps.py +130 -0
- gflow_cli-0.16.0/tests/features/test_locale_picker_include_steps.py +204 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_errors.py +14 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/uv.lock +1 -1
- gflow_cli-0.15.0/tests/api/test_client_launch_kwargs.py +0 -35
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/README.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/active.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/branch-review.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/changelog.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/check.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/doc-review.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/known-issues.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/next.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/plan.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/pr-council-review.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/predict.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/release.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/scenario.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/status.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.continue-here.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.env.template +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.gitattributes +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/CODEOWNERS +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/copilot-instructions.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/dependabot.yml +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/workflows/ci.yml +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/workflows/external-pr-triage.yml +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/workflows/governance-advisory.yml +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/workflows/governance-benchmark.yml +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/workflows/release.yml +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.gitignore +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.gitleaks.toml +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.pre-commit-config.yaml +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.secrets.baseline +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/CLAUDE.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/CONFIGURATION.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/CONTRIBUTING.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/DISCLAIMER.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/GEMINI.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/LICENSE +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/PLAN.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/PR162_MOVIE_CHARACTER_REVIEW.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/RELEASE.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/ROADMAP.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/conftest.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docker-compose.yml +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/AGENT_GUIDE.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/ARCHITECTURE.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/AUTHENTICATION.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/CHARACTER_RECON.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/CONFIGURATION.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/DATA_LAYER.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/DEBUGGING.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/DEMOS.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/DEVELOPMENT.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/E2E_TESTING.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/EXTERNAL_STORAGE.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/GITHUB.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/GOVERNANCE_BENCHMARK.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_data_layer.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_image_batch.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_v0.10.0.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_v0.11.0.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_v0.12.0.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_v0.13.0.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_v0.7.0.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_v0.8.1.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_v0.9.0.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_v0.9.1.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_video_download.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/PROJECT_STATUS.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/SECURITY.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/USER_GUIDE.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/assets/demo-split-pf.gif +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/assets/example-run.gif +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/schemas/movie-handoff.schema.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/2026-05-17-issue-15-handover.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/character-scenario.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/plans/2026-06-01-governance-enforcement-advisory/PLAN.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/plans/2026-06-04-character-create-recording.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/plans/2026-06-06-movie-p0-asyncio-hotfix.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/plans/2026-06-06-movie-p1-composition-manifest.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/plans/2026-06-06-movie-p2-native-identity-voice.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/specs/2026-06-06-movie-consistency-design.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/verifications/2026-05-11-phase-4-stage-g.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/examples/README.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/examples/batch_from_config.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/examples/multi_prompt_t2i.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/examples/sample_config.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/examples/sample_prompts.txt +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/examples/single_image_t2i.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/examples/workflow_chain.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/llms.txt +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/README.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/01_upload_image.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/02_batchAsyncGenerateVideoText.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/04_archive_workflow.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/05_createProject.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/06_batchGenerateImages.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/07_batchGenerateImages_seeded.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/08_batchAsyncGenerateVideoStartAndEndImage.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/09_batchAsyncGenerateVideoReferenceImages.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/10_batchCheckAsyncVideoGenerationStatus_successful.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/11_batchCheckAsyncVideoGenerationStatus_failed.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/12_create_scene.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/13_sceneWorkflows_update.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/14_get_scene_workflows.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/15_commit_flowWorkflow.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/ci/check_doc_links.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/ci/check_materiality.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/ci/check_repo_hygiene.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/debug_editor.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/debug_gen_settings.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/debug_settings.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/_recording_client.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/_spike_common.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/active_plan.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/capture_i2v_frame_slots_dom.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/capture_i2v_intercept_submit.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/capture_i2v_model_select_repro.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/capture_i2v_post_bind_state.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/capture_image_add_media_dom.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/capture_locale_invariants.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/cdp_drive_and_probe.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/character_create_spike.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/character_create_spike_v2.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/dump_character_selectors.js +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/make_project.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/materiality_backtest.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/monitor_pr_38.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/patch_character.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/record_flow_capture.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/skillopt/README.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/skillopt/harness.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/skillopt/tasks.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/spike_char_editor_dom.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/spike_char_gen_capture.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/spike_movie_entity_recon.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/spike_movie_gen_capture.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/spike_movie_picker_select.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/spike_movie_voice_list.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/spike_patch_entity.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/record_demo.ps1 +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/smoke_image.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/smoke_real_chrome_image.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/smoke_video_editor.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/smoke_worker_style.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/verify_chrome_auth_viability.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/skills/README.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/skills/gflow-cli/SKILL.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/skills/plan/SKILL.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/skills/pr-council-review/SKILL.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/skills/predict/SKILL.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/skills/scenario/SKILL.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/skills/status/SKILL.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/sonar-project.properties +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/__main__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/_cli_helpers.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/_retry.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/_sapisidhash.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/character.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/dto.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/image.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/recaptcha.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/scene.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/_common.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/_fingerprint.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/base.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/experimental/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/experimental/bearer.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/experimental/evaluate_fetch.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/experimental/sapisidhash.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/video.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/auth/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/auth/base.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/auth/factory.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/auth/internal_chromium.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/auth/real_chrome.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/auth/strategies.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/auth/verification.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/browser_manager.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/chain.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/chain_manifest.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli_character.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli_data.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli_models.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli_movie.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli_run.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli_scene.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli_video.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/composition.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/config.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/chain_repo.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/migrations/0001_initial.sql +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/migrations/0002_add_cloud_storage.sql +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/migrations/0003_add_scene_tables.sql +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/migrations/0004_add_scene_output_path.sql +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/migrations/0005_add_chain_links.sql +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/migrations/0006_add_operations_metadata.sql +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/migrations/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/models.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/queries.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/recorder.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/redaction.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/repository.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/store.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/image_batch.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/json_output.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/manifest.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/media.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/movie_manifest.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/observability.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/paths.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/profile_store.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/services/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/services/character_create.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/storage.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tasks/lessons.md +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/test_assets/sample_batch.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/test_assets/sample_batch.tsv +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/test_assets/sample_batch_invalid.tsv +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/fixtures/character_gen_response.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/fixtures/patch_entity_response.json +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_aisandbox_auth_error.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_aisandbox_auth_headers.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_bearer_redaction.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_character.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_client.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_client_character.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_client_delete_characters.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_client_generate_character.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_client_image.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_client_patch_entity.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_client_scene.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_concurrency.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_dto.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_image.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_image_dto.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_post_json_aisandbox_auth.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_recaptcha.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_retry.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_routes.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_routes_character.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_routes_scene.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_sapisidhash_helper.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_scene_models.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_video.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_video_request.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_base.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_bearer.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_common.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_evaluate_fetch.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_factory.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_fingerprint.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_sapisidhash.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_transport_timeout.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_ui_automation_batch.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_ui_automation_image_mode.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_ui_character_editor.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/auth/strategies/test_factory.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/auth/strategies/test_strategies.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/auth/test_verification.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_auth_list.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_character.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_character_create.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_data.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_image.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_image_seed_removed.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_models.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_movie.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_run.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_scene.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_video.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_video_chain.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_error_handling.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_helpers.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_movie_manifest.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_t2i_multi_prompt.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/composition/test_character.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/composition/test_compose_prompt.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/composition/test_handoff.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/conftest.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_chain_repo.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_find_incomplete_character.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_models.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_packaging.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_recorder.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_recorder_character.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_redaction.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_repository.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_scene_persistence.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_settings_and_errors.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_store_migrations.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/dev/test_record_flow_capture.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/conftest.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_aisandbox_auth_live.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_auth_verification_e2e.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_chain_e2e.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_character_create_e2e.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_data_layer_e2e.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_i2v_flags_e2e.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_image_batch_e2e.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_image_i2i_ref_cap_e2e.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_json_output_e2e.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_locale_selectors_e2e.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_scene_compose_live.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_transports_e2e.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_video_r2v_ref_cap_e2e.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_video_t2v_e2e.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/auth.feature +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/auth_login.feature +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/character_create.feature +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/character_read.feature +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/conftest.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/image.feature +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/test_auth_login_steps.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/test_auth_steps.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/test_character_create_steps.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/test_character_read_steps.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/test_image_steps.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/test_step_collision_guard.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/test_video_chain_steps.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/video_chain.feature +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/fixtures/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/fixtures/seeded_catalog.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/image_batch/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/image_batch/test_image_manifest.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/image_batch/test_observability_events.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/integration/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/integration/conftest.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/integration/constants.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/integration/test_storage_gcs.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/integration/test_storage_s3.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/scripts/test_capture_locale_invariants.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/scripts/test_check_materiality.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/scripts/test_check_repo_hygiene.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/scripts/test_materiality_backtest.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/services/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/services/test_character_create_redaction.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/services/test_character_create_saga.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/services/test_character_gen_no_direct_post.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/smoke/__init__.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/smoke/test_profile_account_smoke.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/smoke/test_real_flow.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_auth.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_browser_manager.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_chain.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_chain_manifest.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_cli_data.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_config.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_conftest_isolation.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_data_queries.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_documentation_gate.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_errors_403.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_json_output.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_manifest.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_marker_registry.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_media.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_observability.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_paths.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_profile_store.py +0 -0
- {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_smoke.py +0 -0
|
@@ -76,10 +76,12 @@ The `skills/` directory ships installable agent skill docs in plain Markdown wit
|
|
|
76
76
|
| `gflow-cli` | [`skills/gflow-cli/SKILL.md`](skills/gflow-cli/SKILL.md) | User wants to run any `gflow` command — auth, T2V, I2V, T2I, I2I, batch |
|
|
77
77
|
| `predict` | [`skills/predict/SKILL.md`](skills/predict/SKILL.md) | Pre-implementation adversarial analysis before any high-stakes change |
|
|
78
78
|
| `scenario` | [`skills/scenario/SKILL.md`](skills/scenario/SKILL.md) | Edge-case explorer after a predict GO/CAUTION |
|
|
79
|
+
| `plan` | [`skills/plan/SKILL.md`](skills/plan/SKILL.md) | Create a structured task-by-task implementation plan for a feature |
|
|
80
|
+
| `status` | [`skills/status/SKILL.md`](skills/status/SKILL.md) | Show current plan state, progress, and next unchecked task |
|
|
79
81
|
| `pr-council-review` | [`skills/pr-council-review/SKILL.md`](skills/pr-council-review/SKILL.md) | Multi-dimensional PR council review |
|
|
80
82
|
|
|
81
83
|
**Cursor / Aider / Codex / Gemini CLI:** paste or include the relevant `SKILL.md` in your system context.
|
|
82
|
-
**Claude Code:**
|
|
84
|
+
**Claude Code:** the `/gflow:` slash commands in `.claude/commands/gflow/` are auto-discovered when the project is open — no extra setup needed. To register a skill globally, copy the command file to `~/.claude/commands/`.
|
|
83
85
|
**Custom agents:** fetch `skills/gflow-cli/SKILL.md` into your knowledge base before answering gflow questions.
|
|
84
86
|
|
|
85
87
|
The SkillOpt harness at `scripts/dev/skillopt/` measures how accurately each skill guides an agent, and supports multiple providers (Anthropic, OpenAI-compat, Gemini, local models). See [`scripts/dev/skillopt/README.md`](scripts/dev/skillopt/README.md).
|
|
@@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.16.0] — 2026-06-12
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **`--reference-entity` no longer fails on non-Portuguese Flow accounts** ([#170](https://github.com/ffroliva/gflow-cli/issues/170)) — the resource-picker include selectors hardcoded the pt-BR caption "Incluir no comando"; they are now locale-free tier cascades (context-menu `add`-ligature anchor + pt/ru/en text fallback), fixing `gflow image t2i --reference-entity`, movie R2V entity attach, and Vozes voice attach for every account language. Failures are now typed (`TransportTimeoutError`, exit 9) with a locale-neutral remediation hint, the matched selector tier is logged (`include_selector_tier`) for drift telemetry, and a new image-side submit backstop raises `WireFormatError` (exit 7) if a staged character never reaches the wire instead of silently returning a text-only generation. Thanks @papushin7987 for the live-verified report
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **`gflow image upscale <mediaId> --scale 2k|4k`** — upscale a platform-generated image to 2K or 4K (Flow's download-menu 1K/2K/4K options) and save it locally; credit-free. The owning project is resolved from the local catalog (or pass `--project` for images gflow didn't record). 4K requires a Flow Ultra subscription — a non-Ultra 4K request fails fast with exit code 22 (`UpscaleUnavailableError`) rather than a generic 403. Reverse-engineered wire documented in [docs/IMAGE_UPSCALE_RECON.md](docs/IMAGE_UPSCALE_RECON.md); live-verified end-to-end (issue #171)
|
|
19
|
+
|
|
20
|
+
## [0.15.1] — 2026-06-10
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Added `--disable-dev-shm-usage` to Chrome launch args in both `FlowApiClient._persistent_context_kwargs()` and `UiAutomationTransport.setup()` — prevents OOM in Docker containers with the default 64 MB `/dev/shm` allocation; no effect on developer machines with adequate shared memory
|
|
25
|
+
- README Stats badges hardened against shields.io outages — GitHub-stat badges now pass `cacheSeconds=3600` (mitigates shields.io's shared GitHub token-pool exhaustion, the "Unable to select next GitHub token from pool" error) and the PyPI downloads badge moved from `img.shields.io/pypi/dm` to pepy.tech (pypistats rate-limits shields.io upstream)
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- `scripts/diag/` directory — documented home for investigation scripts that require a live authenticated profile; includes `memory_profile.py` (Chrome process-tree RSS profiler for issue #155), `capture_flow_traffic.py`, and `recaptcha_mint.py` (both moved from `scripts/` root via git mv, history preserved)
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- Video status poll now raises `AuthExpiredError` (exit 3) immediately on HTTP 401 from `batchCheckAsyncVideoGenerationStatus` instead of silently timing out after 600 s with a bare `TimeoutError` (exit 1) — session expiry is now detected mid-workflow, not only at login time (issue #156)
|
|
34
|
+
|
|
10
35
|
## [0.15.0] — 2026-06-09
|
|
11
36
|
|
|
12
37
|
### Added
|
|
@@ -1469,7 +1494,9 @@ shell-script template that branches on these codes.
|
|
|
1469
1494
|
|
|
1470
1495
|
First skeleton. Not functional end-to-end yet.
|
|
1471
1496
|
|
|
1472
|
-
[Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.
|
|
1497
|
+
[Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.16.0...HEAD
|
|
1498
|
+
[0.16.0]: https://github.com/ffroliva/gflow-cli/compare/v0.15.1...v0.16.0
|
|
1499
|
+
[0.15.1]: https://github.com/ffroliva/gflow-cli/compare/v0.15.0...v0.15.1
|
|
1473
1500
|
[0.15.0]: https://github.com/ffroliva/gflow-cli/compare/v0.14.0...v0.15.0
|
|
1474
1501
|
[0.14.0]: https://github.com/ffroliva/gflow-cli/compare/v0.13.0...v0.14.0
|
|
1475
1502
|
[0.13.0]: https://github.com/ffroliva/gflow-cli/compare/v0.12.0...v0.13.0
|
|
@@ -14,6 +14,22 @@ Living list of behaviour that's broken, surprising, or limited by design — alo
|
|
|
14
14
|
|
|
15
15
|
## Open
|
|
16
16
|
|
|
17
|
+
### 4K image upscale requires a Flow Ultra subscription
|
|
18
|
+
|
|
19
|
+
- **Status:** **Open** (by design — a Flow platform limit, not a gflow bug)
|
|
20
|
+
- **Severity:** Low · **Affects:** `gflow image upscale --scale 4k` on non-Ultra accounts
|
|
21
|
+
|
|
22
|
+
`gflow image upscale <mediaId> --scale 4k` returns **exit code 22**
|
|
23
|
+
(`UpscaleUnavailableError`) on accounts below the Ultra tier — Flow gates 4K
|
|
24
|
+
upscaling behind Ultra (the web UI shows an "Upgrade" button instead of a 4K
|
|
25
|
+
option). The account tier is reported on the wire as `userPaygateTier` but is
|
|
26
|
+
enforced server-side, so gflow cannot grant 4K locally.
|
|
27
|
+
|
|
28
|
+
**Workaround:** use `--scale 2k` (available on all tiers), or upgrade the Flow
|
|
29
|
+
account to Ultra. If you just upgraded, re-run `gflow auth login --profile <name>`
|
|
30
|
+
to refresh the session before retrying 4K. Wire detail:
|
|
31
|
+
[docs/IMAGE_UPSCALE_RECON.md](docs/IMAGE_UPSCALE_RECON.md) (#171).
|
|
32
|
+
|
|
17
33
|
### Image generation returns HTTP 401 — `aisandbox-pa` generation endpoint
|
|
18
34
|
|
|
19
35
|
- **Status:** **RESOLVED in v0.7.0** — moved to [Resolved](#resolved) section
|
|
@@ -332,7 +348,7 @@ issue and not blocked by any code change in this repo.
|
|
|
332
348
|
|
|
333
349
|
### `UiAutomationTransport` selectors locale-agnostic — issue #24 Phase 5 complete
|
|
334
350
|
|
|
335
|
-
- **Status:** Resolved (pending owner live e2e on non-EN profile) · **Severity:** Low · **Tracking:** [issue #24](https://github.com/ffroliva/gflow-cli/issues/24), [issue #94](https://github.com/ffroliva/gflow-cli/issues/94)
|
|
351
|
+
- **Status:** Resolved (pending owner live e2e on non-EN profile) · **Severity:** Low · **Tracking:** [issue #24](https://github.com/ffroliva/gflow-cli/issues/24), [issue #94](https://github.com/ffroliva/gflow-cli/issues/94), [issue #170](https://github.com/ffroliva/gflow-cli/issues/170)
|
|
336
352
|
|
|
337
353
|
`--lang=en-US` removed in PR #127 (2026-05-30). All selector groups now use
|
|
338
354
|
locale-stable anchors: `IMAGE_MODEL_OPTION_SELECTORS` and
|
|
@@ -343,6 +359,20 @@ issue and not blocked by any code change in this repo.
|
|
|
343
359
|
Playwright kwarg (persists across all in-session navigations). Full resolution
|
|
344
360
|
gate: live e2e with `gflow image t2i` (each model) on a non-EN Chrome profile.
|
|
345
361
|
|
|
362
|
+
**2026-06-12 correction (issue #170):** the "all selector groups" claim above
|
|
363
|
+
had two stragglers — `PICKER_INCLUDE_BUTTON` and `PICKER_CONTEXT_INCLUDE`
|
|
364
|
+
hardcoded the pt-BR caption "Incluir no comando", breaking
|
|
365
|
+
`--reference-entity` (image t2i), movie R2V entity attach, and Vozes voice
|
|
366
|
+
attach on every non-Portuguese account (Flow renders in the ACCOUNT language;
|
|
367
|
+
`?hl=en` cannot override it). Fixed by converting both constants to sequential
|
|
368
|
+
tier cascades — context-menu Tier 1 is the locale-free `add`-ligature menuitem
|
|
369
|
+
scoped to the open menu; the Vozes button has no ligature, so pt/ru/en text
|
|
370
|
+
leads with a lone-iconless-dialog-button structural fallback. The matched tier
|
|
371
|
+
is emitted as `ui_automation_video.include_selector_tier` (drift telemetry),
|
|
372
|
+
exhaustion raises typed `TransportTimeoutError` (exit 9) with a locale-neutral
|
|
373
|
+
remediation hint, and an image-side submit backstop now raises
|
|
374
|
+
`WireFormatError` when a requested entity never rode the wire.
|
|
375
|
+
|
|
346
376
|
**Phase 2 progress (2026-05-25, develop / post-v0.8.1, unreleased):**
|
|
347
377
|
|
|
348
378
|
- **`ONBOARDING_SELECTORS` restructured** — replaced the original 9 English/PT-BR
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gflow-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16.0
|
|
4
4
|
Summary: Unofficial CLI for Google Flow — drive Veo image-to-video generations from the terminal.
|
|
5
5
|
Project-URL: Homepage, https://github.com/ffroliva/gflow-cli
|
|
6
6
|
Project-URL: Issues, https://github.com/ffroliva/gflow-cli/issues
|
|
@@ -196,13 +196,13 @@ gflow CLI → Provider (interchangeable) → Flow (ui_automation) / Mock (te
|
|
|
196
196
|
|
|
197
197
|
## Stats
|
|
198
198
|
|
|
199
|
-
[](https://github.com/ffroliva/gflow-cli/stargazers)
|
|
200
|
-
[](https://github.com/ffroliva/gflow-cli/network/members)
|
|
201
|
-
[](https://github.com/ffroliva/gflow-cli/watchers)
|
|
202
|
-
[](https://github.com/ffroliva/gflow-cli/issues)
|
|
203
|
-
[](https://github.com/ffroliva/gflow-cli/pulls)
|
|
204
|
-
[](https://github.com/ffroliva/gflow-cli/commits/main)
|
|
205
|
-
[](https://github.com/ffroliva/gflow-cli)
|
|
206
|
-
[](https://github.com/ffroliva/gflow-cli/stargazers)
|
|
200
|
+
[](https://github.com/ffroliva/gflow-cli/network/members)
|
|
201
|
+
[](https://github.com/ffroliva/gflow-cli/watchers)
|
|
202
|
+
[](https://github.com/ffroliva/gflow-cli/issues)
|
|
203
|
+
[](https://github.com/ffroliva/gflow-cli/pulls)
|
|
204
|
+
[](https://github.com/ffroliva/gflow-cli/commits/main)
|
|
205
|
+
[](https://github.com/ffroliva/gflow-cli)
|
|
206
|
+
[](https://pepy.tech/project/gflow-cli)
|
|
207
207
|
|
|
208
208
|
If `gflow-cli` saves you time, please ⭐ the repo — it is the cheapest way to support the project.
|
|
@@ -132,13 +132,13 @@ gflow CLI → Provider (interchangeable) → Flow (ui_automation) / Mock (te
|
|
|
132
132
|
|
|
133
133
|
## Stats
|
|
134
134
|
|
|
135
|
-
[](https://github.com/ffroliva/gflow-cli/stargazers)
|
|
136
|
-
[](https://github.com/ffroliva/gflow-cli/network/members)
|
|
137
|
-
[](https://github.com/ffroliva/gflow-cli/watchers)
|
|
138
|
-
[](https://github.com/ffroliva/gflow-cli/issues)
|
|
139
|
-
[](https://github.com/ffroliva/gflow-cli/pulls)
|
|
140
|
-
[](https://github.com/ffroliva/gflow-cli/commits/main)
|
|
141
|
-
[](https://github.com/ffroliva/gflow-cli)
|
|
142
|
-
[](https://github.com/ffroliva/gflow-cli/stargazers)
|
|
136
|
+
[](https://github.com/ffroliva/gflow-cli/network/members)
|
|
137
|
+
[](https://github.com/ffroliva/gflow-cli/watchers)
|
|
138
|
+
[](https://github.com/ffroliva/gflow-cli/issues)
|
|
139
|
+
[](https://github.com/ffroliva/gflow-cli/pulls)
|
|
140
|
+
[](https://github.com/ffroliva/gflow-cli/commits/main)
|
|
141
|
+
[](https://github.com/ffroliva/gflow-cli)
|
|
142
|
+
[](https://pepy.tech/project/gflow-cli)
|
|
143
143
|
|
|
144
144
|
If `gflow-cli` saves you time, please ⭐ the repo — it is the cheapest way to support the project.
|
|
@@ -375,7 +375,8 @@ convenience later.
|
|
|
375
375
|
generate) so Flow's JS sets `entityContext` and passes the WAF; gflow captures `media[]`/`workflows[]`
|
|
376
376
|
from the response. Reuse gflow's prompt-submit + response-capture machinery (`ui_automation.py`), but in
|
|
377
377
|
the character-editor context (NOT the new-project flow). Video `--character` reuse = resource picker
|
|
378
|
-
(
|
|
378
|
+
(search resources → Personagens → *include-in-prompt* context-menu action; captions are localized,
|
|
379
|
+
selectors locale-free since issue #170) → generate; mirrors #123 `_attach_likeness`.
|
|
379
380
|
All selectors **ligature/structural only** (language-agnostic).
|
|
380
381
|
- **Cost reality:** the feature is UI-automation-heavy (new character-editor + picker selectors), not the
|
|
381
382
|
"mostly REST" earlier framing. Structural metadata is REST; the value-generating steps are UI.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Image Upscale — Reverse-Engineering Recon
|
|
2
|
+
|
|
3
|
+
> Status: **recon complete, pre-implementation**. Wire empirically captured 2026-06-11
|
|
4
|
+
> (denon82 Pro account, project `ffb768fb…`). Spikes: `scripts/dev/spike_image_upscale_drive.py`
|
|
5
|
+
> (UI drive + capture) and `scripts/dev/spike_image_upscale_rest_probe.py` (schema + REST probe).
|
|
6
|
+
|
|
7
|
+
## Feature
|
|
8
|
+
|
|
9
|
+
Flow's image editor download menu offers **1K Original / 2K Upscaled / 4K Upscaled**. gflow
|
|
10
|
+
today saves only the 1K original (the pre-signed `fifeUrl` from the generation response). This
|
|
11
|
+
feature adds `gflow image upscale <mediaId> --scale 2k|4k` to fetch the upscaled variant.
|
|
12
|
+
|
|
13
|
+
Scope: **platform-generated images only** (referenced by `mediaId`). Uploaded images are not
|
|
14
|
+
supported by this endpoint. **4K is Ultra-tier-gated**; Pro accounts see "Upgrade" in the UI.
|
|
15
|
+
|
|
16
|
+
## Wire protocol
|
|
17
|
+
|
|
18
|
+
### Endpoint
|
|
19
|
+
```
|
|
20
|
+
POST https://aisandbox-pa.googleapis.com/v1/flow/upsampleImage
|
|
21
|
+
```
|
|
22
|
+
Same host + auth class as image generation (`batchGenerateImages`).
|
|
23
|
+
|
|
24
|
+
### Request body
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"mediaId": "<source-image-uuid>",
|
|
28
|
+
"targetResolution": "UPSAMPLE_IMAGE_RESOLUTION_2K",
|
|
29
|
+
"clientContext": {
|
|
30
|
+
"recaptchaContext": {
|
|
31
|
+
"token": "<reCAPTCHA-Enterprise-token>",
|
|
32
|
+
"applicationType": "RECAPTCHA_APPLICATION_TYPE_WEB"
|
|
33
|
+
},
|
|
34
|
+
"projectId": "<project-that-owns-the-media>",
|
|
35
|
+
"sessionId": ";<epoch_ms>",
|
|
36
|
+
"tool": "PINHOLE",
|
|
37
|
+
"userPaygateTier": "PAYGATE_TIER_ONE"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
- `targetResolution` enum: `UPSAMPLE_IMAGE_RESOLUTION_2K` | `UPSAMPLE_IMAGE_RESOLUTION_4K`.
|
|
42
|
+
1K = original (no API call — gflow already has it).
|
|
43
|
+
- **The FULL `clientContext` is required.** A minimal `{recaptchaContext}` body returns
|
|
44
|
+
**403 even with a valid token** (confirmed by live smoke). All five fields are needed;
|
|
45
|
+
`projectId` (the project owning the media) is load-bearing.
|
|
46
|
+
- `sessionId` format is `;<epoch_ms>` (e.g. `;1781190457842`), same as image generation.
|
|
47
|
+
- `userPaygateTier` is **where the account tier surfaces on the wire** (`PAYGATE_TIER_ONE`
|
|
48
|
+
on a Pro account). It is client-reported telemetry — the server enforces the real tier
|
|
49
|
+
independently (a non-Ultra 4K request 403s regardless), so it is not a security control.
|
|
50
|
+
|
|
51
|
+
### reCAPTCHA action — `IMAGE_GENERATION`
|
|
52
|
+
The token MUST be minted with action **`IMAGE_GENERATION`** (uppercase). reCAPTCHA Enterprise
|
|
53
|
+
scores by action; the guessed `"upsampleImage"` scored low and 403'd. Captured live by hooking
|
|
54
|
+
`grecaptcha.enterprise.execute` (`scripts/dev/spike_image_upscale_recaptcha_action.py`). The
|
|
55
|
+
site key is page-discovered, so it auto-matches; minting on the bootstrap page is fine — the
|
|
56
|
+
action was the only gap. **Live-verified 2026-06-11**: a 2K upscale wrote a 3.8 MB JPEG.
|
|
57
|
+
|
|
58
|
+
### Response
|
|
59
|
+
```json
|
|
60
|
+
{ "encodedImage": "<base64>" }
|
|
61
|
+
```
|
|
62
|
+
- Single field. ~3.8–5.1 MB base64 observed (varies by source image). Decode → write image bytes.
|
|
63
|
+
- Synchronous: one call returns the result. **No async poll/status loop** (unlike video gen).
|
|
64
|
+
|
|
65
|
+
## Transport decision — browser required, REST is dead
|
|
66
|
+
|
|
67
|
+
| Approach | Viable? | Evidence |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| Pure REST / Bearer-only | ❌ No | Bearer `ya29` + **no** reCAPTCHA token → **403** (probed with and without `clientContext`) |
|
|
70
|
+
| Browser reCAPTCHA-mint + POST | ✅ Yes | UI drive returns 200; reuses the existing `batchGenerateImages` transport |
|
|
71
|
+
| Hybrid (browser submit + Bearer poll) | ⚠️ N/A | No poll/download phase exists — response is synchronous inline base64 |
|
|
72
|
+
|
|
73
|
+
**Conclusion:** reCAPTCHA token is **mandatory**. Reuse the existing image-generation reCAPTCHA
|
|
74
|
+
minting path; there is no Bearer-only slice to peel off. See [REST-path capability matrix] — a
|
|
75
|
+
generative-class op stays reCAPTCHA-gated.
|
|
76
|
+
|
|
77
|
+
## Tier gating (4K = Ultra)
|
|
78
|
+
|
|
79
|
+
- 4K is Ultra-only. On Pro, the UI renders "Fazer upgrade" (Upgrade) instead of a clickable 4K.
|
|
80
|
+
- Account tier is **NOT** in `GET /fx/api/auth/session` (only `user` / `expires` / `access_token`).
|
|
81
|
+
It surfaces via the upsell recommendations (`fetchUserRecommendations` onramp list) and is
|
|
82
|
+
enforced server-side. A 4K request on a non-Ultra account is expected to 403 (permission), which
|
|
83
|
+
must be distinguished from a WAF/reCAPTCHA 403.
|
|
84
|
+
- Session staleness is real: an idle session returns `error: ACCESS_TOKEN_REFRESH_NEEDED` and
|
|
85
|
+
re-auths before the call succeeds — so a freshly-upgraded account may need a session refresh
|
|
86
|
+
before 4K unlocks.
|
|
87
|
+
|
|
88
|
+
## UI navigation facts (for the spike/transport)
|
|
89
|
+
|
|
90
|
+
- **Cold-loading `/project/<pid>/edit/<mediaId>` 500s** ("Algo deu errado"). Must land on the
|
|
91
|
+
gallery `/project/<pid>` then click the `a[href*=<mediaId>]` tile (in-app SPA routing).
|
|
92
|
+
- A "What's new" changelog modal overlays the gallery but does **not** block the href tile click.
|
|
93
|
+
- Working selectors (locale leaks into the UI — match language-neutral tokens):
|
|
94
|
+
- Download button: `button:has(i.google-symbols:text-is('download'))`
|
|
95
|
+
- Scale menu item: `[role='menuitem']:has-text('2K')` (and `'4K'`)
|
|
96
|
+
- pt labels are 1K="Tamanho original", 2K/4K="Aumentada" — **never** match on "Aumentada".
|
|
97
|
+
|
|
98
|
+
## Implementation sketch (from `/gflow:predict` GO, 7.5/10)
|
|
99
|
+
|
|
100
|
+
- `api/routes.py`: `UPSAMPLE_IMAGE = f"{FLOW_API_BASE}/flow/upsampleImage"`.
|
|
101
|
+
- `api/image.py`: frozen `UpsampleImageRequest(media_id, target_resolution, recaptcha_token="")`;
|
|
102
|
+
`TargetResolution` enum with `from_cli("2k"|"4k")`.
|
|
103
|
+
- `api/client.py`: `upsample_image()` — mint reCAPTCHA (existing path), POST, validate + decode
|
|
104
|
+
`encodedImage` with `MAX_UPSAMPLE_B64_LEN ≈ 50 MB` cap + `del` + PNG/JPEG magic-byte check
|
|
105
|
+
(mirror `concatenate_scene`).
|
|
106
|
+
- `cli_image.py`: `gflow image upscale <mediaId> --scale 2k|4k [--out]`.
|
|
107
|
+
- `errors.py`: `UpscaleUnavailableError` (exit 22), distinct from WAF/reCAPTCHA 403; **no auto-retry**
|
|
108
|
+
on a 4K 403.
|
|
109
|
+
- Never log `encodedImage`. Record the output via `OperationRecorder` honoring the redaction gate.
|
|
110
|
+
- Discover mediaIds via the existing `gflow data list images`.
|
|
111
|
+
|
|
112
|
+
## Credit cost
|
|
113
|
+
|
|
114
|
+
Image operation → expected **credit-free** (only video generation spends credits). Not yet
|
|
115
|
+
stress-confirmed; treat as free but do not batch aggressively (per-profile WAF heat).
|
|
@@ -34,9 +34,11 @@ Welcome to the `gflow-cli` documentation. This index is the routing layer: it te
|
|
|
34
34
|
| **[docs/DATA_LAYER.md](DATA_LAYER.md)** | Local SQLite catalog: goals, schema, recording flow, redaction, `gflow data` CLI, migrations, extension guide | Anything touching `gflow_cli.data`, debugging missing rows, building I2V/repair tooling, auditing what is stored |
|
|
35
35
|
| **[docs/CHARACTER.md](CHARACTER.md)** | Characters feature spec & system design: domain model, endpoint/cost matrix, sequence diagrams, JSON payloads (I/O), CLI surface, reuse via `referenceEntities` (#145) | Working on `gflow character`, reusing a character in generations, or understanding Flow's character wire protocol |
|
|
36
36
|
| **[docs/MOVIE.md](MOVIE.md)** | `gflow movie` — multi-scene character-consistent films: manifest format, run lifecycle (browser stays open through generate→poll→download), entity-attach mechanism (Personagens right-click), resume/handoff, credits | Working on `gflow movie`, debugging scene generation, or understanding the character-entity attach + consistency model |
|
|
37
|
+
| **[docs/IMAGE_UPSCALE_RECON.md](IMAGE_UPSCALE_RECON.md)** | `gflow image upscale` wire protocol: `upsampleImage` endpoint, full clientContext (projectId/sessionId/tool/userPaygateTier), reCAPTCHA action `IMAGE_GENERATION`, inline base64 response, 4K Ultra-gating, REST-is-dead proof | Working on `gflow image upscale`, debugging the 403/reCAPTCHA path, or understanding Flow's image-upscale wire protocol (#171) |
|
|
37
38
|
| **[tasks/lessons.md](../tasks/lessons.md)** | Running notebook of patterns + reviewer findings, dated and traced to commits | Starting a new phase; debugging "why did the council flag this?" |
|
|
38
39
|
| **[skills/README.md](../skills/README.md)** | Installable agent skill docs (gflow-cli, predict, pr-council-review, scenario) — cross-tool portable Markdown consumed by Claude Code, Cursor, Codex, Gemini CLI, Aider, etc. | Any agent wanting to use gflow-cli correctly |
|
|
39
40
|
| **[scripts/dev/skillopt/README.md](../scripts/dev/skillopt/README.md)** | SkillOpt mock harness — rollout→score loop for measuring and improving skill doc accuracy across multiple LLM providers | Measuring a skill edit's impact; comparing Claude vs GPT-4o vs Gemini on gflow tasks |
|
|
41
|
+
| **[scripts/diag/README.md](../scripts/diag/README.md)** | Diagnostic investigation scripts — run against a live authenticated profile to capture wire samples, measure Chrome memory, or mint reCAPTCHA tokens | Running a one-off investigation against a live Flow session; establishing baseline measurements for issue #155 |
|
|
40
42
|
|
|
41
43
|
## Agent commands
|
|
42
44
|
|
|
@@ -54,6 +56,9 @@ Slash commands for Claude Code, stored in `.claude/commands/gflow/`. All prefixe
|
|
|
54
56
|
| `/gflow:release` | Full release flow (calls `/gflow:changelog` + `/gflow:check`) | Cutting a new version |
|
|
55
57
|
| `/gflow:predict <proposal>` | 5-persona pre-implementation analysis → GO / CAUTION / STOP | Before any high-stakes design decision (new transport, auth change, selector redesign, schema migration) |
|
|
56
58
|
| `/gflow:scenario <feature>` | 12-dimension edge-case explorer → severity-ranked scenario table + BDD skeleton | After predict GO/CAUTION; before `/gflow:plan` |
|
|
59
|
+
| `/gflow:pr-council-review [PR#]` | Multi-dimensional council review of an open PR (5 baseline + adaptive dimensions) | Before merging any non-trivial PR; mandatory for auth/transport/data changes |
|
|
60
|
+
| `/gflow:branch-review` | Same council review run against the current local feature branch (no PR needed) | Pre-PR self-audit; after predict/scenario on a high-stakes branch |
|
|
61
|
+
| `/gflow:doc-review` | Systematic council-driven audit of documentation completeness and drift | Before cutting a release; after major documentation changes |
|
|
57
62
|
|
|
58
63
|
**Governance:** commands are executable docs — they decay like any doc. When a phase advances or a file path changes, update the relevant command in the same commit. `/gflow:release` includes a staleness review step.
|
|
59
64
|
|
|
@@ -90,6 +95,7 @@ Slash commands for Claude Code, stored in `.claude/commands/gflow/`. All prefixe
|
|
|
90
95
|
**"How do I use this project's skills in Cursor / Codex / Gemini CLI / Aider?"** → [skills/README.md](../skills/README.md#use-with-other-agents)
|
|
91
96
|
**"How do I benchmark a skill doc against real tasks?"** → [scripts/dev/skillopt/README.md](../scripts/dev/skillopt/README.md)
|
|
92
97
|
**"How do I compare Claude vs GPT-4o vs Gemini on gflow tasks?"** → `python scripts/dev/skillopt/harness.py --provider openai --model gpt-4o` (see [skillopt README](../scripts/dev/skillopt/README.md))
|
|
98
|
+
**"What does Chrome actually use in RAM during a generation?"** → run `uv run python scripts/diag/memory_profile.py --profile NAME` (see [scripts/diag/README.md](../scripts/diag/README.md))
|
|
93
99
|
**"How do I report a security issue?"** → [SECURITY § Reporting](SECURITY.md#reporting)
|
|
94
100
|
**"What branch do I work on? How do I name it?"** → [DEVELOPMENT § Branching model](DEVELOPMENT.md#branching-model)
|
|
95
101
|
**"How do I handle an external GitHub PR?"** → [GITHUB § Scenario Matrix](GITHUB.md#scenario-matrix)
|
|
@@ -104,7 +110,7 @@ Slash commands for Claude Code, stored in `.claude/commands/gflow/`. All prefixe
|
|
|
104
110
|
**"A gflow command hangs / fails — where do I start?"** → [DEBUGGING § Quick reference](DEBUGGING.md#quick-reference)
|
|
105
111
|
**"Flow's UI broke a selector — how do I diagnose it?"** → [DEBUGGING § Inspecting Flow's live UI](DEBUGGING.md#inspecting-flows-live-ui)
|
|
106
112
|
**"What does each `ui_automation.*` log event mean?"** → [DEBUGGING § Listener & HTTP-layer debugging](DEBUGGING.md#listener--http-layer-debugging)
|
|
107
|
-
**"What was actually live-verified for the latest release?"** → [LIVE_VERIFICATION_v0.13.0](LIVE_VERIFICATION_v0.13.0.md) · prior: [v0.12.0](LIVE_VERIFICATION_v0.12.0.md) · [v0.11.0](LIVE_VERIFICATION_v0.11.0.md) · [v0.10.0](LIVE_VERIFICATION_v0.10.0.md) · [v0.9.1](LIVE_VERIFICATION_v0.9.1.md)
|
|
113
|
+
**"What was actually live-verified for the latest release?"** → v0.15.0 / v0.14.x: no dedicated live-verification doc (CI + the v0.13.0 baseline). Latest doc: [LIVE_VERIFICATION_v0.13.0](LIVE_VERIFICATION_v0.13.0.md) · prior: [v0.12.0](LIVE_VERIFICATION_v0.12.0.md) · [v0.11.0](LIVE_VERIFICATION_v0.11.0.md) · [v0.10.0](LIVE_VERIFICATION_v0.10.0.md) · [v0.9.1](LIVE_VERIFICATION_v0.9.1.md)
|
|
108
114
|
**"What was live-verified for the data layer (PR #58)?"** → [LIVE_VERIFICATION_data_layer](LIVE_VERIFICATION_data_layer.md) — 1 Imagen + 1 Veo credit on denon82, 6-layer ledger (file + magic + Pillow + DB rows + CLI round-trip + structlog)
|
|
109
115
|
**"What was live-verified for the video-download feature (#29)?"** → [LIVE_VERIFICATION_video_download](LIVE_VERIFICATION_video_download.md)
|
|
110
116
|
**"What is the jitter matrix evidence for `gflow image batch`?"** → [`LIVE_VERIFICATION_image_batch.md`](LIVE_VERIFICATION_image_batch.md) — jitter matrix evidence for `gflow image batch` (always-same-project mode)
|
|
@@ -100,10 +100,13 @@ attached by driving Flow's resource picker:
|
|
|
100
100
|
1. Click **Add Media** in the composer (references sub-mode).
|
|
101
101
|
2. Switch to the **Personagens** (Characters) tab.
|
|
102
102
|
3. **Right-click** the entity tile — addressed by entity id as
|
|
103
|
-
`data-tile-id="fe_id_<entityId>"` — and choose
|
|
104
|
-
the context menu
|
|
105
|
-
|
|
106
|
-
|
|
103
|
+
`data-tile-id="fe_id_<entityId>"` — and choose the **include-in-prompt**
|
|
104
|
+
action from the context menu (the `add`-ligature menu item; its caption is
|
|
105
|
+
localized per account language, e.g. "Incluir no comando" on pt-BR or
|
|
106
|
+
"Добавить в запрос" on ru — selectors are locale-free since issue #170).
|
|
107
|
+
*(A plain left-click navigates into the character editor; the inline include
|
|
108
|
+
button on the **Tudo** tab attaches the character's thumbnail as a plain
|
|
109
|
+
image, not the entity.)*
|
|
107
110
|
|
|
108
111
|
This puts `referenceEntities:[{entityId}]` on the
|
|
109
112
|
`video:batchAsyncGenerateVideoReferenceImages` **request**. Flow's **response**
|
|
@@ -105,6 +105,44 @@ UUID=$(gflow image upload hero.png | awk '/Asset UUID:/ {print $3}')
|
|
|
105
105
|
gflow image i2i "make it cinematic" --ref "$UUID"
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
+
## `gflow image upscale`
|
|
109
|
+
|
|
110
|
+
Upscale a **platform-generated** image to 2K or 4K (the same 1K/2K/4K options Flow's
|
|
111
|
+
download menu offers) and save it locally. Uploaded images are not supported.
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
gflow image upscale MEDIA_ID --scale 2k|4k [OPTIONS]
|
|
115
|
+
|
|
116
|
+
Arguments:
|
|
117
|
+
MEDIA_ID UUID of a Flow-generated image (find one with
|
|
118
|
+
`gflow data list images`).
|
|
119
|
+
|
|
120
|
+
Options:
|
|
121
|
+
--scale [2k|4k] Target resolution. 4k requires a Flow Ultra
|
|
122
|
+
subscription; 1k is the original (no upscale).
|
|
123
|
+
--project ID Project that owns the image. Resolved from the local
|
|
124
|
+
catalog when omitted; pass it explicitly for images
|
|
125
|
+
gflow didn't record (e.g. generated in the web UI).
|
|
126
|
+
--out PATH Output directory (see "Output paths" below).
|
|
127
|
+
--profile NAME Profile name (overrides default).
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# Upscale a previously generated image to 2K (project auto-resolved from the catalog)
|
|
132
|
+
gflow image upscale 3a56bb5e-92a2-44f4-9992-3c6a9bf0cd14 --scale 2k
|
|
133
|
+
|
|
134
|
+
# Upscale an image generated in the Flow web UI (not in the local catalog)
|
|
135
|
+
gflow image upscale <mediaId> --scale 2k --project <projectId>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Notes:
|
|
139
|
+
|
|
140
|
+
- **Credit-free** — upscaling is an image operation and spends no credits.
|
|
141
|
+
- **4K is Ultra-only.** On a non-Ultra account a 4K request fails with exit code 22
|
|
142
|
+
(`UpscaleUnavailableError`) and a hint to use `--scale 2k` or upgrade.
|
|
143
|
+
- The result is saved as `<output_dir>/images/<YYYY-MM-DD>/<mediaId>_<scale>.<ext>`
|
|
144
|
+
(extension matches the returned format — usually `.jpg`).
|
|
145
|
+
|
|
108
146
|
## `gflow image t2i`
|
|
109
147
|
|
|
110
148
|
Generate 1–4 images from one text prompt, or run a shell-friendly batch of 1–50
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# Image Upscale Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** Run `/gflow:status --feature image-upscale` to find the next
|
|
4
|
+
> unchecked task. Implement one task at a time. Run `/gflow:check` before every commit.
|
|
5
|
+
|
|
6
|
+
**Goal:** Add `gflow image upscale <mediaId> --scale 2k|4k` so a user can fetch Flow's
|
|
7
|
+
server-side 2K/4K upscaled variant of a platform-generated image and save it locally.
|
|
8
|
+
|
|
9
|
+
**Architecture:** Reuses the existing image-generation reCAPTCHA browser transport — same host
|
|
10
|
+
(`aisandbox-pa.googleapis.com`) and `recaptchaContext` shape as `batchGenerateImages`. New work is
|
|
11
|
+
glue: a route constant, a frozen request value object, a synchronous `FlowApiClient.upsample_image()`
|
|
12
|
+
that mints a reCAPTCHA token, POSTs, and decodes the inline `{encodedImage: base64}` (mirroring
|
|
13
|
+
`concatenate_scene`'s cap + `del` + magic-byte pattern), a new exit-coded error, and a Click
|
|
14
|
+
subcommand. No transport-Protocol change (it's a client-level op like `concatenate_scene`). No new
|
|
15
|
+
auth, no new persistent state, no async poll loop.
|
|
16
|
+
|
|
17
|
+
**Tracking issue:** [#171](https://github.com/ffroliva/gflow-cli/issues/171)
|
|
18
|
+
|
|
19
|
+
**Predict verdict:** GO — confidence 7.5/10. Recon: `docs/IMAGE_UPSCALE_RECON.md`. Scenario matrix
|
|
20
|
+
complete (20 scenarios; 12 Critical/High are must-cover).
|
|
21
|
+
|
|
22
|
+
**Risk register:**
|
|
23
|
+
| Severity | Risk | Mitigation |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| Critical | 403 ambiguity: tier-gate (4K/Pro) vs WAF heat vs expired token all return 403 | Disambiguate by response context; `UpscaleUnavailableError` (exit 22) for tier; **never auto-retry** a 4K 403 |
|
|
26
|
+
| Critical | ~5 MB `encodedImage` base64 leaks into logs / error context | Never log the field; decode then `del`; structlog carries size only |
|
|
27
|
+
| High | Pathological oversized base64 (4K PNG) → OOM | `MAX_UPSAMPLE_B64_LEN` (~50 MB) cap **before** decode; typed error |
|
|
28
|
+
| High | Response missing `encodedImage` / decodes to non-image | `WireFormatError` (redacted discovery payload); PNG/JPEG magic-byte check |
|
|
29
|
+
| High | Per-profile reCAPTCHA/WAF heat (a 4th gated op) | One upscale per invocation; no implicit batch; document the heat |
|
|
30
|
+
| High | mediaId injection / malformed input | UUID allowlist; reject before any request fires |
|
|
31
|
+
| Medium | Selector drift (download button / scale menu) on Flow UI update | Structural-first, locale-neutral selectors (`download`, `2K`/`4K`); re-capture via spike |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## File structure
|
|
36
|
+
|
|
37
|
+
### New files
|
|
38
|
+
```
|
|
39
|
+
src/gflow_cli/api/image_upscale.py (or extend api/image.py)
|
|
40
|
+
UpsampleImageRequest frozen dataclass + TargetResolution enum (from_cli "2k"/"4k")
|
|
41
|
+
tests/api/test_image_upscale.py
|
|
42
|
+
Unit tests: request build, response parse (cap/magic-byte/missing-field), 403 disambiguation
|
|
43
|
+
tests/features/image_upscale.feature
|
|
44
|
+
BDD scenarios from /gflow:scenario (happy 2K, 4K-on-Pro, oversized, malformed mediaId)
|
|
45
|
+
tests/features/test_image_upscale_steps.py
|
|
46
|
+
Step defs mirroring runtime signatures
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Modified files
|
|
50
|
+
```
|
|
51
|
+
src/gflow_cli/api/routes.py
|
|
52
|
+
+ UPSAMPLE_IMAGE = f"{FLOW_API_BASE}/flow/upsampleImage"
|
|
53
|
+
src/gflow_cli/api/client.py
|
|
54
|
+
+ MAX_UPSAMPLE_B64_LEN; + async def upsample_image(media_id, target_resolution, out_path)
|
|
55
|
+
(mint reCAPTCHA via _mint_recaptcha_token; POST; cap+decode+magic-byte; write via image_output_path)
|
|
56
|
+
src/gflow_cli/errors.py
|
|
57
|
+
+ UpscaleUnavailableError (exit 22) registered in EXIT_CODE_MAP; distinct from WAF/reCAPTCHA 403
|
|
58
|
+
src/gflow_cli/cli_image.py
|
|
59
|
+
+ `upscale` Click command: <mediaId> arg, --scale Choice(['2k','4k']), --out, --profile
|
|
60
|
+
src/gflow_cli/paths.py
|
|
61
|
+
(reuse image_output_path; add <mediaId>_<scale> naming if needed)
|
|
62
|
+
docs/USAGE.md, README.md, docs/INDEX.md, CHANGELOG.md
|
|
63
|
+
document the command + the platform-only / Ultra-only constraints
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Task 1 — Error type + exit code (test-first)
|
|
69
|
+
|
|
70
|
+
**What:** Add `UpscaleUnavailableError` (exit 22) for tier-gated/permission failures, distinct from WAF/reCAPTCHA 403.
|
|
71
|
+
|
|
72
|
+
**Files:**
|
|
73
|
+
- `tests/test_errors.py` — assert exit code 22, EXIT_CODE_MAP registration, ordering invariant
|
|
74
|
+
- `src/gflow_cli/errors.py` — new class + map entry
|
|
75
|
+
|
|
76
|
+
**Steps:**
|
|
77
|
+
- [x] Red test: `UpscaleUnavailableError` maps to 22; not equal to WAF 403 code
|
|
78
|
+
- [x] Add the class (RFC 9457 fields: type/title/status/detail/remediation_hint) + register in `EXIT_CODE_MAP`
|
|
79
|
+
- [x] Verify `test_exit_code_map_ordering_invariant` still passes (inheritance trap — see memory)
|
|
80
|
+
|
|
81
|
+
**Tests created (red):**
|
|
82
|
+
- [x] `test_upscale_unavailable_exit_code` — exit 22, distinct from WAF/reCAPTCHA
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Task 2 — Value objects (test-first)
|
|
87
|
+
|
|
88
|
+
**What:** `TargetResolution` enum (`2K`/`4K` ↔ wire `UPSAMPLE_IMAGE_RESOLUTION_*`, `from_cli`) and frozen `UpsampleImageRequest`.
|
|
89
|
+
|
|
90
|
+
**Files:**
|
|
91
|
+
- `tests/api/test_image_upscale.py` — enum mapping, `from_cli` rejects bad values, request immutability
|
|
92
|
+
- `src/gflow_cli/api/image.py` (or new `image_upscale.py`) — enum + dataclass + body builder
|
|
93
|
+
|
|
94
|
+
**Steps:**
|
|
95
|
+
- [x] Red tests: `TargetResolution.from_cli("2k")` → enum; `"1k"`/`"8k"` rejected; request frozen
|
|
96
|
+
- [x] Add enum + `UpsampleImageRequest(media_id, target_resolution, recaptcha_token="")`
|
|
97
|
+
- [x] Body builder → `{mediaId, targetResolution, clientContext:{recaptchaContext:{token}}}`
|
|
98
|
+
- [x] mediaId UUID-allowlist validation (reject malformed before request)
|
|
99
|
+
|
|
100
|
+
**Tests created (red):**
|
|
101
|
+
- [x] `test_target_resolution_from_cli` / `test_target_resolution_rejects_1k_and_unknown`
|
|
102
|
+
- [x] `test_upsample_request_body_shape`
|
|
103
|
+
- [x] `test_media_id_uuid_validation`
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Task 3 — Client `upsample_image()` (test-first)
|
|
108
|
+
|
|
109
|
+
**What:** Synchronous client method: mint reCAPTCHA, POST `upsampleImage`, parse `{encodedImage}` with cap + magic-byte, write file. Route constant added.
|
|
110
|
+
|
|
111
|
+
**Files:**
|
|
112
|
+
- `tests/api/test_image_upscale.py` — mocked transport/HTTP: happy path, oversized cap, missing field, non-image bytes, 403→typed error, no-retry on 4K 403, `encodedImage` never logged
|
|
113
|
+
- `src/gflow_cli/api/routes.py` — `UPSAMPLE_IMAGE`
|
|
114
|
+
- `src/gflow_cli/api/client.py` — `MAX_UPSAMPLE_B64_LEN = 50 * 1024 * 1024`; `upsample_image(...)`
|
|
115
|
+
|
|
116
|
+
**Steps:**
|
|
117
|
+
- [x] Red tests for: 200 happy (decode → PNG/JPEG bytes written); response > cap → typed error before decode; missing `encodedImage` → `WireFormatError` (redacted); decoded bytes fail magic-byte → typed error
|
|
118
|
+
- [x] Red tests for 403 disambiguation: tier 403 → `UpscaleUnavailableError` (no retry); WAF 403 → existing `WafRejectionError`; expired-token 401 → existing refresh+single-retry
|
|
119
|
+
- [x] Red test: structlog capture asserts `encodedImage` value never present in any event
|
|
120
|
+
- [x] Add route + method; reuse `_mint_recaptcha_token("upscaleImage" or correct action)`; single Page checkout (no nested checkout — use `context.request` if aux call needed)
|
|
121
|
+
- [x] Decode mirrors `concatenate_scene` (cap → `b64decode` → magic-byte → `del encoded`)
|
|
122
|
+
- [x] Write via `paths.image_output_path` as `<mediaId>_<scale>.<ext>` (ext from magic byte)
|
|
123
|
+
|
|
124
|
+
**Tests created (red):**
|
|
125
|
+
- [x] `test_upsample_happy_2k`, `test_upsample_oversized_rejected`, `test_upsample_missing_field`,
|
|
126
|
+
`test_upsample_non_image_bytes`, `test_upsample_4k_pro_403_no_retry`,
|
|
127
|
+
`test_upsample_waf_403_distinct`, `test_upsample_encoded_image_never_logged`
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Task 4 — CLI surface (test-first)
|
|
132
|
+
|
|
133
|
+
**What:** `gflow image upscale <mediaId> --scale 2k|4k [--out] [--profile]` with self-contained `--help`.
|
|
134
|
+
|
|
135
|
+
**Files:**
|
|
136
|
+
- `tests/test_cli_image.py` — Click invocation: arg/flag parsing, `--scale` Choice, exit codes, 4K/Pro hint, malformed mediaId usage error (no request), structlog `upscale_started/completed/unavailable`
|
|
137
|
+
- `src/gflow_cli/cli_image.py` — `upscale` command
|
|
138
|
+
|
|
139
|
+
**Steps:**
|
|
140
|
+
- [x] Red tests: happy invocation calls `upsample_image` with mapped enum; `--scale 8k` rejected by Click; `--scale 1k` rejected with "1k is the original" hint; malformed mediaId → usage error, no HTTP
|
|
141
|
+
- [x] Red test: 4K-on-Pro path surfaces exit 22 + Ultra-only remediation; no auto-retry
|
|
142
|
+
- [x] Implement command; emit `upscale_started/completed/unavailable` (stable keys); `--help` states platform-only + Ultra-only constraints + "find mediaId via `gflow data list images`"
|
|
143
|
+
- [x] Record the output asset via `OperationRecorder` honoring the redaction gate; wrap callback in try/except `DataStoreError`
|
|
144
|
+
|
|
145
|
+
**Tests created (red):**
|
|
146
|
+
- [x] `test_upscale_cli_happy`, `test_upscale_cli_scale_choice`, `test_upscale_cli_1k_rejected`,
|
|
147
|
+
`test_upscale_cli_bad_media_id`, `test_upscale_cli_4k_pro_exit22`
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Task 5 — BDD scaffold + green
|
|
152
|
+
|
|
153
|
+
**What:** Gherkin feature covering all Critical+High scenarios; step defs mirror runtime signatures.
|
|
154
|
+
|
|
155
|
+
**Files:**
|
|
156
|
+
- `tests/features/image_upscale.feature` — happy 2K, 4K-on-Pro, oversized, malformed mediaId
|
|
157
|
+
- `tests/features/test_image_upscale_steps.py` — typed step defs (mirror signatures — see memory)
|
|
158
|
+
|
|
159
|
+
**Steps:**
|
|
160
|
+
- [x] Add the four `/gflow:scenario` BDD scenarios as a feature file
|
|
161
|
+
- [x] Implement step defs against the real command; assert exit codes + redaction
|
|
162
|
+
- [x] All BDD green
|
|
163
|
+
|
|
164
|
+
**Tests created:**
|
|
165
|
+
- [x] BDD: 2K happy, 4K/Pro exit 22, oversized rejected, malformed mediaId usage error
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Task 6 — Docs + recon finalize
|
|
170
|
+
|
|
171
|
+
**What:** User-facing docs + cross-references; recon already written.
|
|
172
|
+
|
|
173
|
+
**Files:**
|
|
174
|
+
- `docs/USAGE.md` — `gflow image upscale` section (workflow: `data list images` → `upscale`)
|
|
175
|
+
- `README.md` command table; `docs/INDEX.md` route to `IMAGE_UPSCALE_RECON.md`
|
|
176
|
+
- `docs/KNOWN_ISSUES.md` — note 4K Ultra-gating + per-profile WAF heat from the extra gated op
|
|
177
|
+
- `CHANGELOG.md` `[Unreleased]` — `feat(image): upscale to 2K/4K (#171)`
|
|
178
|
+
|
|
179
|
+
**Steps:**
|
|
180
|
+
- [x] Write usage + constraints (platform-only, Ultra-only, credit-free expectation)
|
|
181
|
+
- [x] Index the recon doc; cross-link spikes
|
|
182
|
+
- [x] CHANGELOG entry referencing #171
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Task 7 — Full gates + PR
|
|
187
|
+
|
|
188
|
+
**What:** Green `/gflow:check`; open PR to `develop`.
|
|
189
|
+
|
|
190
|
+
**Steps:**
|
|
191
|
+
- [x] `/gflow:check` green (ruff + format + `pyright src` + pytest ≥ 80% on changed dirs)
|
|
192
|
+
- [x] Live smoke (opt-in, supervised): one real 2K upscale on a known mediaId (credit-free) confirms wire still matches
|
|
193
|
+
- [x] PR `feature/image-upscale` → `develop`, `Closes #171`
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Definition of done
|
|
198
|
+
|
|
199
|
+
- [x] All task steps checked off
|
|
200
|
+
- [x] `/gflow:check` green (ruff / format / pyright / pytest ≥ 80% coverage)
|
|
201
|
+
- [x] `CHANGELOG.md` `[Unreleased]` updated (`#171`)
|
|
202
|
+
- [x] Docs updated (`USAGE.md`, `README.md`, `INDEX.md`, `KNOWN_ISSUES.md`)
|
|
203
|
+
- [x] BDD feature covers all Critical + High scenarios from `/gflow:scenario`
|
|
204
|
+
- [x] `encodedImage` proven absent from logs (test) — Critical mitigation verified
|
|
205
|
+
- [x] 4K/Pro 403 → exit 22, no auto-retry — Critical mitigation verified
|
|
206
|
+
- [x] No `# TODO` in diff without a tracked issue link
|