gflow-cli 0.24.0__tar.gz → 0.26.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.24.0 → gflow_cli-0.26.0}/.env.template +4 -3
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/CHANGELOG.md +117 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/PKG-INFO +1 -1
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/CONFIGURATION.md +4 -2
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/INDEX.md +1 -1
- gflow_cli-0.26.0/docs/LIVE_VERIFICATION_v0.25.0.md +97 -0
- gflow_cli-0.26.0/docs/LIVE_VERIFICATION_v0.26.0.md +69 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/MCP.md +2 -2
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/SECURITY.md +1 -1
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/pyproject.toml +1 -1
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/__init__.py +1 -1
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/client.py +19 -1
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/dto.py +35 -2
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/image.py +11 -2
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/transports/ui_automation.py +10 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/transports/ui_automation_video.py +377 -80
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/video.py +31 -15
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/cli.py +1 -1
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/config.py +67 -7
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/models.py +2 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/recorder.py +6 -1
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/repository.py +57 -62
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/mcp/tools.py +166 -21
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/paths.py +19 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/worker/daemon.py +28 -1
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_client_image.py +23 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_image_dto.py +30 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_video.py +1 -1
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_video_request.py +14 -1
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/test_ui_automation_video.py +95 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/data/test_repository.py +48 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/conftest.py +4 -2
- gflow_cli-0.26.0/tests/mcp/test_tools_helpers.py +313 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/mcp/test_tools_wired.py +42 -0
- gflow_cli-0.26.0/tests/test_config.py +456 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_paths.py +33 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/worker/test_daemon.py +55 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/uv.lock +1 -1
- gflow_cli-0.24.0/tests/mcp/test_tools_helpers.py +0 -149
- gflow_cli-0.24.0/tests/test_config.py +0 -227
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/README.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/commands/gflow/active.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/commands/gflow/branch-review.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/commands/gflow/changelog.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/commands/gflow/check.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/commands/gflow/doc-review.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/commands/gflow/issue-assessment.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/commands/gflow/issue-resolve.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/commands/gflow/known-issues.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/commands/gflow/next.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/commands/gflow/plan.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/commands/gflow/pr-council-review.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/commands/gflow/predict.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/commands/gflow/release.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/commands/gflow/scenario.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/commands/gflow/sonar.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.claude/commands/gflow/status.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.gitattributes +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.github/CODEOWNERS +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.github/copilot-instructions.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.github/dependabot.yml +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.github/workflows/ci.yml +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.github/workflows/external-pr-triage.yml +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.github/workflows/governance-advisory.yml +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.github/workflows/governance-benchmark.yml +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.github/workflows/main-base-guard.yml +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.github/workflows/release.yml +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.gitignore +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.gitleaks.toml +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.pre-commit-config.yaml +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/.secrets.baseline +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/AGENTS.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/CLAUDE.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/CONFIGURATION.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/CONTRIBUTING.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/DISCLAIMER.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/GEMINI.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/KNOWN_ISSUES.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/LICENSE +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/PLAN.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/README.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/RELEASE.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/ROADMAP.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/conftest.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docker-compose.yml +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/AGENT_GUIDE.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/AGENT_UI_E2E.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/AGENT_UI_RECON.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/ARCHITECTURE.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/AUTHENTICATION.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/CHARACTER.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/CHARACTER_RECON.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/DATA_LAYER.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/DEBUGGING.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/DEMOS.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/DEVELOPMENT.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/E2E_TESTING.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/EXTERNAL_STORAGE.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/GITHUB.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/GOVERNANCE_BENCHMARK.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/IMAGE_UPSCALE_RECON.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_data_layer.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_image_batch.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.10.0.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.11.0.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.12.0.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.13.0.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.16.0.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.17.0.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.18.0.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.19.0.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.20.0.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.20.1.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.21.0.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.22.0.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.23.0.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.24.0.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.7.0.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.8.1.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.9.0.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_v0.9.1.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/LIVE_VERIFICATION_video_download.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/MOVIE.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/PROJECT_STATUS.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/PROMPT_EXPANSION.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/TOOLS.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/USAGE.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/USER_GUIDE.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/assets/demo-split-pf.gif +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/assets/example-run.gif +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/assets/examples.webp +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/medium_tutorial.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/schemas/movie-handoff.schema.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/sonar-cleanup-tracker.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/superpowers/plans/2026-06-12-issue-174-library-ui-attach/PLAN.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/superpowers/plans/2026-06-22-mcp-server/PLAN.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/superpowers/plans/2026-06-22-mcp-server/PREDICT.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/superpowers/plans/2026-06-22-mcp-server/SCENARIO.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/superpowers/plans/2026-06-22-prompt-expansion/PLAN.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/superpowers/plans/2026-06-22-prompt-expansion/PREDICT.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/superpowers/plans/2026-06-22-prompt-expansion/SCENARIO.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/superpowers/plans/2026-06-24-gflow-studio-scaffold/PLAN.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/superpowers/plans/2026-06-24-rest-api-layer/PLAN.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/superpowers/plans/2026-06-26-mcp-e2e-test/PLAN.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/superpowers/research/2026-06-27-tool-abstraction-evaluation.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/docs/superpowers/specs/2026-06-29-issue-assessment-workflow-design.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/examples/README.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/examples/batch_from_config.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/examples/multi_prompt_t2i.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/examples/sample_config.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/examples/sample_prompts.txt +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/examples/single_image_t2i.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/examples/workflow_chain.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/llms.txt +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/samples/README.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/samples/captured/01_upload_image.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/samples/captured/02_batchAsyncGenerateVideoText.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/samples/captured/04_archive_workflow.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/samples/captured/05_createProject.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/samples/captured/06_batchGenerateImages.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/samples/captured/07_batchGenerateImages_seeded.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/samples/captured/08_batchAsyncGenerateVideoStartAndEndImage.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/samples/captured/09_batchAsyncGenerateVideoReferenceImages.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/samples/captured/10_batchCheckAsyncVideoGenerationStatus_successful.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/samples/captured/11_batchCheckAsyncVideoGenerationStatus_failed.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/samples/captured/12_create_scene.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/samples/captured/13_sceneWorkflows_update.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/samples/captured/14_get_scene_workflows.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/samples/captured/15_commit_flowWorkflow.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/ci/check_doc_links.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/ci/check_materiality.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/ci/check_repo_hygiene.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/debug_editor.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/debug_gen_settings.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/debug_settings.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/_recording_client.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/_spike_common.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/active_plan.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/analyze_agent_ui_capture.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/capture_i2v_frame_slots_dom.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/capture_i2v_intercept_submit.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/capture_i2v_model_select_repro.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/capture_i2v_post_bind_state.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/capture_image_add_media_dom.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/capture_locale_invariants.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/cdp_drive_and_probe.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/character_create_spike.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/character_create_spike_v2.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/dump_character_selectors.js +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/make_project.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/materiality_backtest.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/monitor_pr_38.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/patch_character.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/skillopt/README.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/skillopt/harness.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/skillopt/tasks.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/spike_char_editor_dom.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/spike_char_gen_capture.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/spike_image_upscale_capture.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/spike_image_upscale_drive.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/spike_image_upscale_recaptcha_action.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/spike_image_upscale_rest_probe.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/spike_issue170_picker_locale_recon.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/spike_issue174_library_ui_recon.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/spike_movie_attach_payload.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/spike_movie_entity_recon.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/spike_movie_gen_capture.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/spike_movie_picker_select.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/spike_movie_voice_list.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/spike_patch_entity.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/dev/spike_patchright.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/diag/README.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/diag/capture_flow_traffic.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/diag/memory_profile.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/diag/recaptcha_mint.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/e2e/agentic_image_e2e.ps1 +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/e2e/capture_agent_toggle.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/record_demo.ps1 +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/smoke_image.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/smoke_real_chrome_image.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/smoke_video_editor.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/smoke_worker_style.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/scripts/verify_chrome_auth_viability.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/skills/README.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/skills/gflow-cli/SKILL.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/skills/issue-assessment/SKILL.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/skills/issue-resolve/SKILL.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/skills/plan/SKILL.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/skills/pr-council-review/SKILL.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/skills/predict/SKILL.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/skills/scenario/SKILL.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/skills/status/SKILL.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/sonar-project.properties +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/__main__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/_cli_helpers.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/_engine.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/_retry.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/_sapisidhash.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/character.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/image_upscale.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/recaptcha.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/routes.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/scene.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/transports/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/transports/_common.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/transports/_fingerprint.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/transports/base.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/transports/drivers/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/transports/drivers/agentic.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/transports/drivers/base.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/transports/drivers/classic.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/transports/drivers/factory.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/transports/experimental/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/transports/experimental/bearer.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/transports/experimental/evaluate_fetch.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/api/transports/experimental/sapisidhash.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/auth/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/auth/base.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/auth/cookies.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/auth/factory.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/auth/internal_chromium.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/auth/real_chrome.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/auth/strategies.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/auth/verification.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/browser_manager.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/chain.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/chain_manifest.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/cli_character.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/cli_data.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/cli_image.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/cli_models.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/cli_movie.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/cli_run.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/cli_scene.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/cli_tools.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/cli_video.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/composition.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/chain_repo.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/migrations/0001_initial.sql +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/migrations/0002_add_cloud_storage.sql +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/migrations/0003_add_scene_tables.sql +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/migrations/0004_add_scene_output_path.sql +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/migrations/0005_add_chain_links.sql +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/migrations/0006_add_operations_metadata.sql +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/migrations/0007_queue.sql +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/migrations/0008_add_operation_expanded_prompt.sql +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/migrations/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/queries.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/redaction.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/data/store.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/errors.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/exceptions.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/image_batch.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/json_output.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/manifest.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/mcp/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/mcp/prompts.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/mcp/resources.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/mcp/server.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/media.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/movie_manifest.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/observability.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/profile_store.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/services/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/services/character_create.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/storage.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/tools/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/tools/banned.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/tools/builtin/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/tools/builtin/creative-director.toml +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/tools/expander.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/tools/invocation.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/tools/loader.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/tools/registry.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/tools/runtime.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/tools/spec.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/ui/app.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/ui/server.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/src/gflow_cli/worker/queue.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tasks/lessons.md +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/test_assets/sample_batch.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/test_assets/sample_batch.tsv +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/test_assets/sample_batch_invalid.tsv +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/fixtures/character_gen_response.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/fixtures/patch_entity_response.json +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_aisandbox_auth_error.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_aisandbox_auth_headers.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_bearer_redaction.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_character.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_client.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_client_character.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_client_delete_characters.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_client_generate_character.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_client_launch_kwargs.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_client_patch_entity.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_client_scene.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_client_upscale.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_concurrency.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_dto.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_engine.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_image.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_image_upscale.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_post_json_aisandbox_auth.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_recaptcha.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_retry.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_routes.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_routes_character.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_routes_scene.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_sapisidhash_helper.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/test_scene_models.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/conftest.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/drivers/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/drivers/test_agentic.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/drivers/test_factory.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/test_base.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/test_bearer.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/test_common.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/test_evaluate_fetch.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/test_factory.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/test_fingerprint.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/test_sapisidhash.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/test_transport_timeout.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/test_ui_automation.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/test_ui_automation_batch.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/test_ui_automation_image_mode.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/api/transports/test_ui_character_editor.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/auth/strategies/test_factory.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/auth/strategies/test_strategies.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/auth/test_cookies.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/auth/test_verification.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_cli_auth_list.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_cli_character.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_cli_character_create.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_cli_data.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_cli_image.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_cli_image_seed_removed.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_cli_image_selector_drift.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_cli_image_upscale.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_cli_models.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_cli_movie.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_cli_run.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_cli_scene.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_cli_tools.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_cli_video.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_cli_video_chain.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_error_handling.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_helpers.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_movie_manifest.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_settings_validation.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/cli/test_t2i_multi_prompt.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/composition/test_character.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/composition/test_compose_prompt.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/composition/test_handoff.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/conftest.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/data/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/data/test_chain_repo.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/data/test_find_incomplete_character.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/data/test_models.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/data/test_packaging.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/data/test_recorder.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/data/test_recorder_character.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/data/test_redaction.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/data/test_scene_persistence.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/data/test_settings_and_errors.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/data/test_store_migrations.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/dev/test_recording_client.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/test_aisandbox_auth_live.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/test_auth_verification_e2e.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/test_chain_e2e.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/test_character_create_e2e.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/test_daemon_e2e.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/test_data_layer_e2e.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/test_i2v_flags_e2e.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/test_image_batch_e2e.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/test_image_i2i_ref_cap_e2e.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/test_json_output_e2e.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/test_locale_selectors_e2e.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/test_scene_compose_live.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/test_tools_e2e.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/test_transports_e2e.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/test_video_r2v_ref_cap_e2e.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/e2e/test_video_t2v_e2e.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/auth.feature +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/auth_login.feature +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/character_create.feature +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/character_read.feature +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/conftest.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/image.feature +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/image_upscale.feature +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/locale_picker_include.feature +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/test_auth_login_steps.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/test_auth_steps.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/test_character_create_steps.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/test_character_read_steps.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/test_image_steps.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/test_image_upscale_steps.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/test_locale_picker_include_steps.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/test_step_collision_guard.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/test_video_agent_ui_steps.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/test_video_chain_steps.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/video_agent_ui.feature +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/features/video_chain.feature +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/fixtures/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/fixtures/seeded_catalog.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/image_batch/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/image_batch/test_image_manifest.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/image_batch/test_observability_events.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/integration/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/integration/conftest.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/integration/constants.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/integration/test_storage_gcs.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/integration/test_storage_s3.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/mcp/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/mcp/conftest.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/mcp/test_server.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/mcp/test_stdio_transport.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/scripts/test_analyze_agent_ui_capture.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/scripts/test_capture_locale_invariants.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/scripts/test_check_materiality.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/scripts/test_check_repo_hygiene.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/scripts/test_materiality_backtest.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/services/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/services/test_character_create_redaction.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/services/test_character_create_saga.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/services/test_character_gen_no_direct_post.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/smoke/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/smoke/test_profile_account_smoke.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/smoke/test_real_flow.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_auth.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_browser_manager.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_chain.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_chain_manifest.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_cli_data.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_conftest_isolation.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_data_queries.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_documentation_gate.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_errors.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_errors_403.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_json_output.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_manifest.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_marker_registry.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_media.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_observability.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_profile_store.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/test_smoke.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/tools/__init__.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/tools/test_banned.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/tools/test_expander.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/tools/test_invocation.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/tools/test_loader.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/tools/test_registry.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/tools/test_runtime.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/tools/test_spec.py +0 -0
- {gflow_cli-0.24.0 → gflow_cli-0.26.0}/tests/ui/test_app.py +0 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# gflow-cli — example environment variables.
|
|
2
|
-
# Copy to `.env` in the directory where you invoke `gflow`
|
|
3
|
-
#
|
|
4
|
-
#
|
|
2
|
+
# Copy to `.env` in the directory where you invoke `gflow` (project-local
|
|
3
|
+
# overrides) or to `$GFLOW_CLI_HOME/.env` (machine-wide defaults; used by
|
|
4
|
+
# processes with arbitrary working directories, e.g. the MCP server) and
|
|
5
|
+
# uncomment what you want to override. On conflicts the CWD `.env` wins.
|
|
5
6
|
# All variables are OPTIONAL — defaults work out of the box for most users.
|
|
6
7
|
# Lines below are commented to show the SHIPPED DEFAULT — uncomment to override.
|
|
7
8
|
|
|
@@ -7,6 +7,123 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.26.0] — 2026-07-06
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Reference a generated image in `image i2i` by its Flow UUID (`gflow_generate_image`,
|
|
15
|
+
`reference_images`)**: pass a generated image's media UUID as a reference and gflow
|
|
16
|
+
attaches it by **selecting the already-existing asset in Flow's reference picker** —
|
|
17
|
+
it does **not** upload a duplicate copy (avoiding duplication is the preferred path).
|
|
18
|
+
The asset's tile is located by its media id in the thumbnail URL (robust to
|
|
19
|
+
display-name collisions), surfaced by a display-name search when it isn't already
|
|
20
|
+
visible, and attached in place. When the asset can't be located (e.g. it's in a
|
|
21
|
+
different project's picker), gflow falls back to uploading its on-disk local file. A
|
|
22
|
+
UUID that isn't in your catalog still attaches by media id (no error). Live-verified:
|
|
23
|
+
a generated image's UUID → i2i output that references it, with no duplicate upload.
|
|
24
|
+
- **Generated images now record their Flow display name**: the display name is extracted
|
|
25
|
+
from the `batchGenerateImages` response's `workflows[]` array (previously ignored) and
|
|
26
|
+
persisted in the asset catalog — the searchable label the media picker shows, and what
|
|
27
|
+
the UUID-reference path searches by. (Original find and approach by **@C1ph3r404**,
|
|
28
|
+
#253/#255.)
|
|
29
|
+
|
|
30
|
+
## [0.25.0] — 2026-07-06
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- **Follow-up review fixes for remote image UUIDs (#237/#245)**: a post-merge
|
|
35
|
+
multi-angle review surfaced regressions and defects now corrected:
|
|
36
|
+
- Image `i2i` with a Flow media-id ref that isn't in the local catalog is no
|
|
37
|
+
longer rejected — UUID→display-name resolution is applied only to the video
|
|
38
|
+
paths (image refs attach by media id). Restores the `i2i` pass-through.
|
|
39
|
+
- The generation result envelope's `flow_media_id` again carries the real
|
|
40
|
+
media id (it was returning the asset's `flow_workflow_id`); the workflow id
|
|
41
|
+
is exposed under its own `flow_workflow_id` key.
|
|
42
|
+
- An in-catalog asset with no display name no longer returns its raw UUID as
|
|
43
|
+
the picker search term (which timed out); it fails fast with a clear error.
|
|
44
|
+
- Remote picker tiles match the display name exactly (`get_by_role(exact=True)`),
|
|
45
|
+
so a name that is a substring of another can't silently attach the wrong image.
|
|
46
|
+
- The R2V picker-close timeout matches the I2V budget (was a too-tight 8s that
|
|
47
|
+
aborted slow-but-successful attaches).
|
|
48
|
+
- `_attach_reference_audio` selects its tile by ARIA role+name instead of an
|
|
49
|
+
apostrophe-unsafe `:has-text()` selector.
|
|
50
|
+
|
|
51
|
+
- **Remote-UUID video attach reworked to use local upload (#237)**: live
|
|
52
|
+
verification found the original mechanism — resolve the UUID to a display name
|
|
53
|
+
and select its tile in Flow's resource picker — could never work for generated
|
|
54
|
+
media: Flow's asset search does not index generation prompts, and generated
|
|
55
|
+
assets carry no display name, so the picker returned "No results found" and the
|
|
56
|
+
attach timed out. The UUID is now resolved to the image's on-disk local file and
|
|
57
|
+
attached through the existing, already-verified file-upload path. The failing
|
|
58
|
+
picker path is no longer used for video UUID refs. (Automatic download-by-media-id
|
|
59
|
+
for the rare case where the local file was pruned is a planned follow-up; for now
|
|
60
|
+
that case fails fast with a clear "Reference Not On Disk" error.)
|
|
61
|
+
|
|
62
|
+
- **`gflow_generate_image` no longer silently saves a video as an image**: the
|
|
63
|
+
agentic image path has no explicit image-mode toggle — Flow's conversational
|
|
64
|
+
agent infers image-vs-video from the prompt and can produce a *video*, whose
|
|
65
|
+
tile is then scraped as if it were an image. The MP4 bytes were saved with a
|
|
66
|
+
`.png` suffix and catalogued as an image, a silent corruption that only
|
|
67
|
+
surfaced far downstream (Flow 400-rejects the file as an i2v frame → text-only
|
|
68
|
+
#125 fallback). `download_image` now detects video magic bytes (ISO-BMFF / WebM)
|
|
69
|
+
and fails loud with a `WireFormatError` naming the cause, instead of writing the
|
|
70
|
+
corrupt file. (Root cause — the agentic agent producing a video for an image
|
|
71
|
+
request — is tracked separately; this stops the silent corruption.)
|
|
72
|
+
|
|
73
|
+
- **Rejected i2v/r2v frame uploads now fail loud instead of falling back to T2V**:
|
|
74
|
+
`_upload_via_open_dialog` matched the `uploadImage` response by URL only and
|
|
75
|
+
ignored its status, so a Flow 4xx rejection (e.g. an invalid image file) was
|
|
76
|
+
treated as success — the code committed an empty slot and the generation
|
|
77
|
+
silently produced a text-only video (#125). The upload status is now checked and
|
|
78
|
+
a rejection aborts with a clear error.
|
|
79
|
+
|
|
80
|
+
### Added
|
|
81
|
+
|
|
82
|
+
- **Remote image UUIDs in `gflow_generate_video` (#237)**: I2V (`initial_frame` /
|
|
83
|
+
`end_frame`) and R2V (`reference_images`) now accept a generated image's Flow UUID,
|
|
84
|
+
not just a local file path — pipe the output of an image generation straight into a
|
|
85
|
+
video generation. At enqueue time the UUID is resolved to the image's local file
|
|
86
|
+
(already on disk from the image generation) and attached through the same proven
|
|
87
|
+
file-upload path used for a local `--initial-frame`, so no picker name-search is
|
|
88
|
+
involved. A UUID that isn't in your asset catalog fails fast with a clear "Reference
|
|
89
|
+
Not Found" error, and a catalogued asset whose local file is missing fails fast with
|
|
90
|
+
"Reference Not On Disk" (re-generate it or pass a local path) — both instead of a
|
|
91
|
+
long browser timeout. (Contributed by @C1ph3r404; the attach mechanism was
|
|
92
|
+
reworked during maintainer live-verification — see Fixed below.)
|
|
93
|
+
|
|
94
|
+
### Fixed
|
|
95
|
+
|
|
96
|
+
- **Removed a shadowed duplicate `Settings.daemon_token` field definition (#243)**: the
|
|
97
|
+
class body defined `daemon_token` twice; Python silently kept only the second
|
|
98
|
+
(aliased) one, leaving the first as dead code that a future edit could touch without
|
|
99
|
+
effect. The surviving definition's contract (both `GFLOW_CLI_DAEMON_TOKEN` and
|
|
100
|
+
`GFLOW_DAEMON_TOKEN` accepted) is now pinned by tests, along with a guard that the
|
|
101
|
+
field is defined exactly once.
|
|
102
|
+
|
|
103
|
+
- **`$GFLOW_CLI_HOME/.env` now loads as a dotenv fallback (#240)**: `config.py`'s own
|
|
104
|
+
module docstring promised a `.env` fallback "from CWD or `$GFLOW_CLI_HOME/.env`", but
|
|
105
|
+
the implementation only ever read the CWD file — a key placed in the home `.env` was
|
|
106
|
+
silently ignored (easy to miss under the prompt tools' never-fatal contract, and it
|
|
107
|
+
bites any process whose CWD is not a project root: the MCP server launched by a
|
|
108
|
+
desktop client, a worker service, a scheduled task). `Settings` now defaults the
|
|
109
|
+
standard pydantic-settings `_env_file` init kwarg to `($GFLOW_CLI_HOME/.env, ./.env)`
|
|
110
|
+
per construction, so explicit `Settings(_env_file=...)` — including the disable idiom
|
|
111
|
+
`_env_file=None` — keeps working. Precedence: process env vars beat both files, and a
|
|
112
|
+
CWD `.env` beats `$GFLOW_CLI_HOME/.env`.
|
|
113
|
+
- **Home resolution is coherent across every channel**: the home used to locate the
|
|
114
|
+
home `.env` now matches what `Settings.home` reports when `GFLOW_CLI_HOME` comes
|
|
115
|
+
from the process env (case-insensitively, as the env source matches it), from a
|
|
116
|
+
`GFLOW_CLI_HOME` entry in the CWD `.env`, or is set-but-empty (treated as unset
|
|
117
|
+
rather than `Path('.')`). The home `.env` itself cannot relocate home (circular).
|
|
118
|
+
- **Docs reconciled**: `docs/CONFIGURATION.md` § ".env loading", `docs/SECURITY.md`
|
|
119
|
+
(Gemini-key locations) and `.env.template` previously documented CWD-only loading
|
|
120
|
+
and now describe the two-file behavior; the `gflow serve` token hint no longer
|
|
121
|
+
points at `.env.local`, which was never a loaded file.
|
|
122
|
+
- **Worker daemon**: `FlowApiClient` constructions in `process_task` now receive the
|
|
123
|
+
daemon's cached settings instead of re-reading `.env` files live per task, so a
|
|
124
|
+
mid-run edit to the home `.env` can no longer produce a task whose client config
|
|
125
|
+
disagrees with the parameters the task derived from `get_settings()`.
|
|
126
|
+
|
|
10
127
|
## [0.24.0] — 2026-07-01
|
|
11
128
|
|
|
12
129
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gflow-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.26.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
|
|
@@ -312,9 +312,11 @@ predictable external storage keys, set the bucket prefix in
|
|
|
312
312
|
|
|
313
313
|
## .env loading
|
|
314
314
|
|
|
315
|
-
`gflow-cli` (via [`pydantic-settings`](https://docs.pydantic.dev/latest/concepts/pydantic_settings/)) loads
|
|
315
|
+
`gflow-cli` (via [`pydantic-settings`](https://docs.pydantic.dev/latest/concepts/pydantic_settings/)) loads **two** `.env` files at startup: `$GFLOW_CLI_HOME/.env` (machine-wide defaults — useful for processes whose working directory is arbitrary, like the MCP server or a worker service) and a `.env` in the **current working directory** (project-local overrides). On conflicting keys the CWD file wins.
|
|
316
316
|
|
|
317
|
-
|
|
317
|
+
The home used for the first file is resolved from the `GFLOW_CLI_HOME` env var, else a `GFLOW_CLI_HOME` entry in the CWD `.env`, else the platform default — the same home `Settings.home` reports. (By construction the home `.env` cannot relocate home itself; set the env var or the CWD `.env` instead.)
|
|
318
|
+
|
|
319
|
+
Variables already set in the actual environment always beat both `.env` files. Anything explicitly passed on the CLI beats everything else.
|
|
318
320
|
|
|
319
321
|
Use [`.env.template`](../.env.template) as your starting point:
|
|
320
322
|
|
|
@@ -117,7 +117,7 @@ Slash commands for Claude Code, stored in `.claude/commands/gflow/`. All prefixe
|
|
|
117
117
|
**"A gflow command hangs / fails — where do I start?"** → [DEBUGGING § Quick reference](DEBUGGING.md#quick-reference)
|
|
118
118
|
**"Flow's UI broke a selector — how do I diagnose it?"** → [DEBUGGING § Inspecting Flow's live UI](DEBUGGING.md#inspecting-flows-live-ui)
|
|
119
119
|
**"What does each `ui_automation.*` log event mean?"** → [DEBUGGING § Listener & HTTP-layer debugging](DEBUGGING.md#listener--http-layer-debugging)
|
|
120
|
-
**"What was actually live-verified for the latest release?"** → latest: [LIVE_VERIFICATION_v0.24.0](LIVE_VERIFICATION_v0.24.0.md) (--project parity across CLI + MCP — automated coverage; live gen auth-gated). Prior: [v0.23.0](LIVE_VERIFICATION_v0.23.0.md) (MCP generation wiring proven live end-to-end — tool→worker→real Flow REST→structured-error translation; final image-write blocked by an expired session, environmental. #222 macOS fix reporter-verified e2e on Apple Silicon). Prior: [v0.22.0](LIVE_VERIFICATION_v0.22.0.md) (Tools framework — automated/CI coverage complete; credit/key-gated live feature run is a pending owner gate, see the doc) · [v0.21.0](LIVE_VERIFICATION_v0.21.0.md) (MCP server over stdio + HTTP/SSE — credit-free protocol handshake; 4 tools / 2 prompts / 3 resources confirmed on stdout) · [v0.20.1](LIVE_VERIFICATION_v0.20.1.md) · [v0.20.0](LIVE_VERIFICATION_v0.20.0.md) · [v0.19.0](LIVE_VERIFICATION_v0.19.0.md) · [v0.18.0](LIVE_VERIFICATION_v0.18.0.md) · [v0.17.0](LIVE_VERIFICATION_v0.17.0.md) · [v0.16.0](LIVE_VERIFICATION_v0.16.0.md) · [v0.13.0](LIVE_VERIFICATION_v0.13.0.md) · [v0.12.0](LIVE_VERIFICATION_v0.12.0.md) · [v0.11.0](LIVE_VERIFICATION_v0.11.0.md) · [v0.10.0](LIVE_VERIFICATION_v0.10.0.md) · [v0.9.1](LIVE_VERIFICATION_v0.9.1.md) · [v0.9.0](LIVE_VERIFICATION_v0.9.0.md) · [v0.8.1](LIVE_VERIFICATION_v0.8.1.md) · [v0.7.0](LIVE_VERIFICATION_v0.7.0.md)
|
|
120
|
+
**"What was actually live-verified for the latest release?"** → latest: [LIVE_VERIFICATION_v0.26.0](LIVE_VERIFICATION_v0.26.0.md) (**image i2i by generated-image UUID proven live e2e GREEN** — the existing asset is *selected in place* by its media UUID, no duplicate upload, producing an i2i output that references it; plus generated-image `display_name` capture, credited @C1ph3r404). Prior: [v0.25.0](LIVE_VERIFICATION_v0.25.0.md) (**#237 remote-UUID i2v proven live e2e GREEN** — a real 8s 720×1280 interpolation from a generated image's UUID, after the picker-search attach was reworked to local upload; #240 home-`.env` matrix live; plus two silent-failure guards root-caused live: video-as-image download rejection and rejected-upload fail-loud). Prior: [v0.24.0](LIVE_VERIFICATION_v0.24.0.md) (--project parity across CLI + MCP — automated coverage; live gen auth-gated). Prior: [v0.23.0](LIVE_VERIFICATION_v0.23.0.md) (MCP generation wiring proven live end-to-end — tool→worker→real Flow REST→structured-error translation; final image-write blocked by an expired session, environmental. #222 macOS fix reporter-verified e2e on Apple Silicon). Prior: [v0.22.0](LIVE_VERIFICATION_v0.22.0.md) (Tools framework — automated/CI coverage complete; credit/key-gated live feature run is a pending owner gate, see the doc) · [v0.21.0](LIVE_VERIFICATION_v0.21.0.md) (MCP server over stdio + HTTP/SSE — credit-free protocol handshake; 4 tools / 2 prompts / 3 resources confirmed on stdout) · [v0.20.1](LIVE_VERIFICATION_v0.20.1.md) · [v0.20.0](LIVE_VERIFICATION_v0.20.0.md) · [v0.19.0](LIVE_VERIFICATION_v0.19.0.md) · [v0.18.0](LIVE_VERIFICATION_v0.18.0.md) · [v0.17.0](LIVE_VERIFICATION_v0.17.0.md) · [v0.16.0](LIVE_VERIFICATION_v0.16.0.md) · [v0.13.0](LIVE_VERIFICATION_v0.13.0.md) · [v0.12.0](LIVE_VERIFICATION_v0.12.0.md) · [v0.11.0](LIVE_VERIFICATION_v0.11.0.md) · [v0.10.0](LIVE_VERIFICATION_v0.10.0.md) · [v0.9.1](LIVE_VERIFICATION_v0.9.1.md) · [v0.9.0](LIVE_VERIFICATION_v0.9.0.md) · [v0.8.1](LIVE_VERIFICATION_v0.8.1.md) · [v0.7.0](LIVE_VERIFICATION_v0.7.0.md)
|
|
121
121
|
**"Where is the reverse-engineered wire protocol for a feature?"** → the `*_RECON.md` design docs: [CHARACTER_RECON](CHARACTER_RECON.md) (Flow character entity protocol), [IMAGE_UPSCALE_RECON](IMAGE_UPSCALE_RECON.md) (`/v1/flow/upsampleImage` wire). Naming convention: one `<FEATURE>_RECON.md` per reverse-engineered surface, kept as the durable spec after the feature ships.
|
|
122
122
|
**"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)
|
|
123
123
|
**"What was live-verified for the video-download feature (#29)?"** → [LIVE_VERIFICATION_video_download](LIVE_VERIFICATION_video_download.md)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Live Verification — v0.25.0
|
|
2
|
+
|
|
3
|
+
Release date: 2026-07-06. Headline change: **remote image UUIDs in
|
|
4
|
+
`gflow_generate_video`** (#237), plus the `$GFLOW_CLI_HOME/.env` dotenv fallback
|
|
5
|
+
(#240 — the minor-bump reason) and the shadowed-duplicate `Settings.daemon_token`
|
|
6
|
+
removal (#243). Live verification of the #237 attach found — and this cycle fixed —
|
|
7
|
+
that the originally-merged mechanism could not work, and surfaced two pre-existing
|
|
8
|
+
silent-failure guards that are now fixed too.
|
|
9
|
+
|
|
10
|
+
All live runs: 2026-07-06, headed Playwright, profile `ffroliva`, against real Flow.
|
|
11
|
+
|
|
12
|
+
## Scope
|
|
13
|
+
|
|
14
|
+
| Change | Surface | Verdict |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| **#237** — UUID image refs in `gflow_generate_video` | `mcp/tools.py`, `paths.py` | ✅ **Live e2e GREEN** after the attach was reworked (below) |
|
|
17
|
+
| **#240** — `$GFLOW_CLI_HOME/.env` fallback | `config.py` | ✅ Live CLI precedence matrix + pinning tests |
|
|
18
|
+
| **#243** — duplicate `daemon_token` removed | `config.py` | ✅ Automated (`tests/test_config.py`) — internal fix, no live surface |
|
|
19
|
+
| Hardening — video-as-image download guard | `api/client.py`, `paths.py` | ✅ Unit-verified; root-caused live |
|
|
20
|
+
| Hardening — rejected-upload fail-loud | `ui_automation_video.py` | ✅ Unit-verified; root-caused live |
|
|
21
|
+
|
|
22
|
+
## #237 — remote image UUIDs → video (the rework)
|
|
23
|
+
|
|
24
|
+
**The originally-merged mechanism was broken.** It resolved the UUID to a *display
|
|
25
|
+
name* and searched Flow's resource picker for the tile. Instrumented live
|
|
26
|
+
diagnostics (picker aria-tree + screenshots) proved generated media never appear
|
|
27
|
+
in that picker: Flow's asset search does not index generation prompts, and
|
|
28
|
+
generated assets carry no display name (0 of 190 catalogued assets had one), so
|
|
29
|
+
the picker returned **"No results found"** and every attach timed out — in scratch
|
|
30
|
+
projects and in the asset's own project alike.
|
|
31
|
+
|
|
32
|
+
**Fix (this cycle):** the UUID is resolved to the image's on-disk local file
|
|
33
|
+
(already saved by the image generation) and attached through the same proven
|
|
34
|
+
file-upload path used for a local `--initial-frame`. No picker name-search.
|
|
35
|
+
|
|
36
|
+
### Live end-to-end result — GREEN
|
|
37
|
+
|
|
38
|
+
`gflow_generate_video(mode="i2v", initial_frame="<generated-image-UUID>", …)`
|
|
39
|
+
driven through the **real stdio MCP server** (`gflow mcp run`), start frame a
|
|
40
|
+
generated image (valid JPEG, `60dcb880…`). 5-layer ledger:
|
|
41
|
+
|
|
42
|
+
1. **File count**: exactly one MP4 written (`d7749780-…-2ae354.mp4`).
|
|
43
|
+
2. **Magic bytes**: `00 00 00 20 66 74 79 70 69 73 6f 6d` (`ftypisom`, valid ISO-BMFF MP4), 5.30 MB.
|
|
44
|
+
3. **Shape**: `ffprobe` → h264, **720×1280** (9:16 as requested), duration **8.0 s**.
|
|
45
|
+
4. **Structlog / wire invariants**: upload `status: 200`; generate route
|
|
46
|
+
**`batchAsyncGenerateVideoStartImage`** (the true i2v route, **not** the T2V
|
|
47
|
+
`batchAsyncGenerateVideoText` route); captured `startImage` bound; task
|
|
48
|
+
`status: completed`.
|
|
49
|
+
5. **User-confirmable artifact**: a mid-clip frame shows the wooden **"v0.25.0"**
|
|
50
|
+
sign *animating* (drifting dust, camera push-in, "Veo" watermark) — a genuine
|
|
51
|
+
interpolation of the still start frame.
|
|
52
|
+
|
|
53
|
+
### Fail-fast paths (also live-verified, credit-free)
|
|
54
|
+
|
|
55
|
+
- Unknown UUID → RFC 9457 **`Reference Not Found`** in ~1.5 s via the real MCP
|
|
56
|
+
server (no browser, no timeout).
|
|
57
|
+
- Catalogued asset with no on-disk file → **`Reference Not On Disk`** (re-generate
|
|
58
|
+
or pass a local path; auto download-by-media-id is a planned follow-up).
|
|
59
|
+
|
|
60
|
+
## #240 — `$GFLOW_CLI_HOME/.env` fallback (live CLI matrix)
|
|
61
|
+
|
|
62
|
+
Marker `GFLOW_CLI_DB_PATH` observed via `gflow data list images` from a foreign
|
|
63
|
+
CWD: home-`.env` only loads ✅; CWD `.env` beats home ✅; process env beats both ✅;
|
|
64
|
+
set-but-empty `GFLOW_CLI_HOME` treated as unset (default-home `.env` still loads)
|
|
65
|
+
✅. Pinned by `tests/test_config.py`.
|
|
66
|
+
|
|
67
|
+
## Hardening — two silent-failure guards (root-caused during this verification)
|
|
68
|
+
|
|
69
|
+
The first e2e attempts failed at the frame upload with a confusing i2v→T2V (#125)
|
|
70
|
+
fallback. Root cause was **not** the pipeline: the "image" fed as the start frame
|
|
71
|
+
(`f94bdd3f…_1.png`) was actually an **MP4 video** — its magic bytes are `ftypisom`.
|
|
72
|
+
|
|
73
|
+
1. **`gflow_generate_image` produced a video-as-`.png`.** The agentic image path
|
|
74
|
+
has no explicit image-mode toggle (`switch_to_image_mode` is a no-op) — Flow's
|
|
75
|
+
conversational agent infers image-vs-video from the prompt and produced a video,
|
|
76
|
+
whose tile `await_images` scraped as an image. The MP4 bytes were saved `.png`
|
|
77
|
+
(`extension_from_magic` only knows image formats) and catalogued as an image.
|
|
78
|
+
**Fix:** `download_image` now rejects video magic bytes (`looks_like_video`:
|
|
79
|
+
ISO-BMFF / WebM) with a `WireFormatError` instead of writing the corrupt file.
|
|
80
|
+
2. **Rejected uploads were treated as success.** `_upload_via_open_dialog` matched
|
|
81
|
+
the `uploadImage` response by URL only and ignored its status, so a Flow **400**
|
|
82
|
+
(Flow correctly rejecting the non-image bytes) committed an empty slot → T2V
|
|
83
|
+
fallback. **Fix:** the upload status is checked (`_upload_rejection_message`) and
|
|
84
|
+
a 4xx aborts loudly.
|
|
85
|
+
|
|
86
|
+
Both are pre-existing (present in 0.24.0) and unit-tested. The underlying "agentic
|
|
87
|
+
agent produces a video for an image request" is tracked as a separate follow-up;
|
|
88
|
+
these guards convert the resulting silent corruption into a clear, actionable error.
|
|
89
|
+
|
|
90
|
+
## Automated coverage
|
|
91
|
+
|
|
92
|
+
- `pyright src`: 0 errors. `ruff check` / `ruff format --check`: clean.
|
|
93
|
+
`check_doc_links.py`, `check_repo_hygiene.py`: clean.
|
|
94
|
+
- New unit tests: UUID→local-path resolution + fail-fast cases (`tests/mcp`),
|
|
95
|
+
`looks_like_video` + `download_image` video rejection (`tests/test_paths.py`,
|
|
96
|
+
`tests/api/test_client_image.py`), `_upload_rejection_message`
|
|
97
|
+
(`tests/api/transports/test_ui_automation_video.py`).
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Live Verification — v0.26.0
|
|
2
|
+
|
|
3
|
+
Release date: 2026-07-06. Headline: **reference a generated image in `image i2i`
|
|
4
|
+
by its Flow UUID**, attached by **selecting the already-existing asset** in Flow's
|
|
5
|
+
reference picker rather than uploading a duplicate copy (the founder principle:
|
|
6
|
+
avoid duplication). Plus generated images now record their Flow **display name**
|
|
7
|
+
(the searchable picker label), extracted from the response's `workflows[]` array.
|
|
8
|
+
|
|
9
|
+
Live run: 2026-07-06, headed Playwright, profile `ffroliva`, real Flow.
|
|
10
|
+
|
|
11
|
+
## Scope
|
|
12
|
+
|
|
13
|
+
| Change | Surface | Verdict |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| Image i2i UUID ref → **select existing asset** (no duplicate) | `mcp/tools.py`, `worker/daemon.py`, `api/image.py`, `api/transports/ui_automation*.py` | ✅ **Live e2e GREEN** |
|
|
16
|
+
| Generated-image `display_name` from `workflows[]` | `api/dto.py`, `data/recorder.py` | ✅ Unit-tested (real captured sample); credited @C1ph3r404 |
|
|
17
|
+
|
|
18
|
+
## Mechanism
|
|
19
|
+
|
|
20
|
+
An `image i2i` `reference_images` entry that is a Flow media UUID is resolved at
|
|
21
|
+
enqueue time (best-effort, never errors — an uncatalogued UUID still attaches by
|
|
22
|
+
media id, PR #245) to the asset's `display_name` + on-disk `local_path`. The
|
|
23
|
+
transport then **prefers selecting the existing asset in place**:
|
|
24
|
+
|
|
25
|
+
1. Locate the tile by the **media UUID in its thumbnail URL** (`img[src*=<uuid>]`)
|
|
26
|
+
— robust to display-name collisions, needs no search term.
|
|
27
|
+
2. If not already visible, **search the display name** to surface it, then re-locate
|
|
28
|
+
by UUID.
|
|
29
|
+
3. Attach in place. (The image picker attaches on tile-click and auto-closes; the
|
|
30
|
+
code also handles the video-style explicit "Add to Prompt" include.)
|
|
31
|
+
4. **Fallback — local upload** only when the asset can't be located (e.g. it lives
|
|
32
|
+
in a different project's picker) and a local file exists.
|
|
33
|
+
|
|
34
|
+
## Live end-to-end result — GREEN
|
|
35
|
+
|
|
36
|
+
`gflow_generate_image(prompt="the same rustic workshop wall, wider shot, more
|
|
37
|
+
tools", reference_images=["60dcb880-…" (a generated image's UUID)],
|
|
38
|
+
project="0f4e7eaa-…" (the asset's project), profile="ffroliva")` via the real
|
|
39
|
+
stdio MCP server. 5-layer ledger:
|
|
40
|
+
|
|
41
|
+
1. **Attach path**: structlog `ui_automation_video.image_ref_selected_existing`
|
|
42
|
+
fired — and **no** `image_ref_upload_fallback` / `image_uploaded` event. The
|
|
43
|
+
existing asset was selected; **no duplicate was uploaded**.
|
|
44
|
+
2. **Wire**: the generation ran the `batchGenerateImages` route carrying the
|
|
45
|
+
reference `imageInput` — the ref reached the generation, not a plain t2i.
|
|
46
|
+
3. **File**: exactly one output written, `bee1e8a9-…_1.jpg`, 893 KB.
|
|
47
|
+
4. **Magic bytes**: `ff d8 ff e0` (valid JPEG); task `status: completed`.
|
|
48
|
+
5. **User-confirmable artifact**: the output shows the **same** rustic workshop
|
|
49
|
+
wall and the "v0.25.0" sign as the referenced image, as a wider shot with more
|
|
50
|
+
tools — the i2i reference visibly took.
|
|
51
|
+
|
|
52
|
+
### Pre-fix note
|
|
53
|
+
|
|
54
|
+
The first live attempt selected the asset correctly but errored looking for a
|
|
55
|
+
separate "Add to Prompt" button — the image picker attaches on tile-click and
|
|
56
|
+
auto-closes (one step), unlike the video r2v picker. Fixed to treat an
|
|
57
|
+
auto-closed dialog as success; the re-run above is GREEN. (A hung Chrome holding
|
|
58
|
+
the profile's `SingletonLock` also caused two transient `launch_persistent_context`
|
|
59
|
+
failures between runs — cleared by killing the process + removing the lock.)
|
|
60
|
+
|
|
61
|
+
## Automated coverage
|
|
62
|
+
|
|
63
|
+
- `_enrich_image_refs` unit tests (`tests/mcp/test_tools_helpers.py`): enriches a
|
|
64
|
+
catalogued ref with display_name + local_path; partial meta when no on-disk file;
|
|
65
|
+
uncatalogued UUID passes through with no error and no `ref_meta`.
|
|
66
|
+
- `display_name` extraction tests (`tests/api/test_image_dto.py`) against the real
|
|
67
|
+
captured `06_batchGenerateImages.json` sample.
|
|
68
|
+
- Full suite green (1994 passed; the one deselected `test_packaging` case is a
|
|
69
|
+
network-dependent sdist build, unrelated). `pyright src` 0 errors, ruff clean.
|
|
@@ -45,8 +45,8 @@ Both Click CLI (`src/gflow_cli/cli.py`) and MCP Server (`src/gflow_cli/mcp/`) ar
|
|
|
45
45
|
The server registers three protocol surfaces:
|
|
46
46
|
|
|
47
47
|
### Tools (Executable actions)
|
|
48
|
-
* `gflow_generate_image(prompt, model, aspect, count, seed, reference_images, tools, profile, project)`: Triggers text-to-image / image-to-image (Imagen / Nano Banana). `reference_images` switches to i2i; `project` generates into an existing Flow project id (mirrors CLI `--project`).
|
|
49
|
-
* `gflow_generate_video(prompt, mode, aspect, initial_frame, end_frame, reference_images, tools, profile, project)`: Triggers vertical or landscape video generation (Veo). `mode` is `t2v`/`i2v`/`r2v`; `i2v` requires `initial_frame`, `r2v` requires `reference_images`; `project` generates into an existing Flow project id (mirrors CLI `--project`).
|
|
48
|
+
* `gflow_generate_image(prompt, model, aspect, count, seed, reference_images, tools, profile, project)`: Triggers text-to-image / image-to-image (Imagen / Nano Banana). `reference_images` switches to i2i and accepts **either a local file path or a generated image's Flow media UUID**. A UUID reference is attached by **selecting the already-existing asset in Flow's reference picker — no duplicate copy is uploaded** (locating the tile by the media id in its thumbnail URL, and searching the recorded display name to surface it when needed); gflow falls back to uploading the asset's on-disk local file only when it can't be located in place (e.g. it lives in a different project's picker). `project` generates into an existing Flow project id (mirrors CLI `--project`) — pass the reference's project to keep it selectable in place.
|
|
49
|
+
* `gflow_generate_video(prompt, mode, aspect, initial_frame, end_frame, reference_images, tools, profile, project)`: Triggers vertical or landscape video generation (Veo). `mode` is `t2v`/`i2v`/`r2v`; `i2v` requires `initial_frame`, `r2v` requires `reference_images`; `project` generates into an existing Flow project id (mirrors CLI `--project`). `initial_frame`, `end_frame`, and `reference_images` each accept **either a local file path or the Flow image UUID of a generated asset** — pass a generated image's id straight in to chain image→video, and gflow attaches it for you (the UUID is resolved to the asset's already-on-disk local file and uploaded as the frame; no manual download/re-upload step). A UUID that isn't in your local asset catalog is rejected up front with a clear "Reference Not Found" error; a catalogued asset whose local file is no longer on disk gives a "Reference Not On Disk" error (re-generate it or pass a local path).
|
|
50
50
|
* `gflow_list_projects(profile, limit)`: Queries SQLite catalog for recent generation folders.
|
|
51
51
|
* `gflow_list_characters(profile)`: Lists Flow Character entities (requires an active browser session).
|
|
52
52
|
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
|
|
40
40
|
Not used by v0.4.0a2's reverse-engineered Flow provider. Documented here in advance of `GFLOW_CLI_PROVIDER=official`.
|
|
41
41
|
|
|
42
|
-
- **Location:** `$GFLOW_CLI_GEMINI_API_KEY` env var, optionally loaded from a `.env` file in the directory where you invoke `gflow`
|
|
42
|
+
- **Location:** `$GFLOW_CLI_GEMINI_API_KEY` env var, optionally loaded from a `.env` file in the directory where you invoke `gflow` or from `$GFLOW_CLI_HOME/.env` (CWD wins on conflicts; see [CONFIGURATION.md](CONFIGURATION.md#env-loading)). Treat BOTH locations as secret-bearing files: keep `$GFLOW_CLI_HOME/.env` user-readable only and out of shared images/backups.
|
|
43
43
|
- **In memory:** Held only in the `Settings` dataclass, never logged.
|
|
44
44
|
- **In transit:** Sent only to `generativelanguage.googleapis.com` over HTTPS.
|
|
45
45
|
- **Rotate:** Set a new value in `.env`, restart the CLI. No persistence beyond the env var.
|
|
@@ -64,7 +64,7 @@ from gflow_cli.errors import (
|
|
|
64
64
|
WafRejectionError,
|
|
65
65
|
WireFormatError,
|
|
66
66
|
)
|
|
67
|
-
from gflow_cli.paths import adjust_key_extension, character_output_path
|
|
67
|
+
from gflow_cli.paths import adjust_key_extension, character_output_path, looks_like_video
|
|
68
68
|
from gflow_cli.storage import AnyPath, storage_path, write_asset_async
|
|
69
69
|
|
|
70
70
|
if TYPE_CHECKING:
|
|
@@ -1097,6 +1097,24 @@ class FlowApiClient:
|
|
|
1097
1097
|
_raise_for_non_retryable(resp, await resp.text(), route=route)
|
|
1098
1098
|
body = await resp.body()
|
|
1099
1099
|
|
|
1100
|
+
# Fail loud if an image request downloaded video content. The agentic
|
|
1101
|
+
# gflow_generate_image path has no explicit image-mode toggle — Flow's
|
|
1102
|
+
# conversational agent infers image-vs-video from the prompt and can
|
|
1103
|
+
# produce a video, whose tile await_images then scrapes as if it were an
|
|
1104
|
+
# image. Saving those bytes with an image suffix is a silent corruption
|
|
1105
|
+
# that only surfaces far downstream (e.g. Flow 400-rejects the file as an
|
|
1106
|
+
# i2v frame -> #125 text-only fallback). Catch it at the download.
|
|
1107
|
+
if looks_like_video(body):
|
|
1108
|
+
raise WireFormatError(
|
|
1109
|
+
detail=(
|
|
1110
|
+
"image download returned video content (ISO-BMFF/WebM magic "
|
|
1111
|
+
"bytes) — the agentic conversational agent likely produced a "
|
|
1112
|
+
"video instead of an image. Use a Classic UI profile "
|
|
1113
|
+
"(GFLOW_CLI_PREFER_CLASSIC=1) or rephrase the prompt."
|
|
1114
|
+
),
|
|
1115
|
+
route=route,
|
|
1116
|
+
)
|
|
1117
|
+
|
|
1100
1118
|
# Resolve the write target: local Path or cloud UPath.
|
|
1101
1119
|
# Compute a relative key from out_path so cloud keys mirror the local
|
|
1102
1120
|
# directory structure (images/YYYY-MM-DD/media_id_N.ext).
|
|
@@ -8,7 +8,7 @@ KeyErrors leak.
|
|
|
8
8
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
|
-
from dataclasses import dataclass
|
|
11
|
+
from dataclasses import dataclass, replace
|
|
12
12
|
from typing import TYPE_CHECKING, Any, Literal, cast
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
@@ -128,6 +128,10 @@ class GeneratedImage:
|
|
|
128
128
|
fife_url: str # CDN URL — usually expires after ~6 hours
|
|
129
129
|
dimensions: tuple[int, int] # (width, height)
|
|
130
130
|
media_generation_id: str | None = None
|
|
131
|
+
# Flow-assigned display name (from the response's `workflows[]` array). This
|
|
132
|
+
# is the searchable label the media picker shows — recorded so a generated
|
|
133
|
+
# image can be referenced by name later. Original find by @C1ph3r404 (#253).
|
|
134
|
+
display_name: str | None = None
|
|
131
135
|
|
|
132
136
|
@property
|
|
133
137
|
def is_signed_url(self) -> bool:
|
|
@@ -172,8 +176,37 @@ class GeneratedImage:
|
|
|
172
176
|
if not isinstance(media, list):
|
|
173
177
|
msg = "unexpected batchGenerateImages response shape: media is not a list"
|
|
174
178
|
raise ValueError(msg)
|
|
179
|
+
# Flow returns display names in a sibling `workflows[]` array keyed by
|
|
180
|
+
# workflow id (mirrors AssetInfo.from_upload_response). Build the lookup
|
|
181
|
+
# once and inject the name onto each parsed image. (Find by @C1ph3r404.)
|
|
182
|
+
workflow_names = cls._workflow_display_names(data.get("workflows"))
|
|
175
183
|
items = cast("list[dict[str, Any]]", media)
|
|
176
|
-
|
|
184
|
+
results: list[GeneratedImage] = []
|
|
185
|
+
for item in items:
|
|
186
|
+
img = cls.from_response_item(item)
|
|
187
|
+
name = workflow_names.get(img.workflow_id)
|
|
188
|
+
if name:
|
|
189
|
+
img = replace(img, display_name=name)
|
|
190
|
+
results.append(img)
|
|
191
|
+
return results
|
|
192
|
+
|
|
193
|
+
@staticmethod
|
|
194
|
+
def _workflow_display_names(workflows: object) -> dict[str, str]:
|
|
195
|
+
"""Map workflow id → displayName from the response's ``workflows[]``."""
|
|
196
|
+
names: dict[str, str] = {}
|
|
197
|
+
if not isinstance(workflows, list):
|
|
198
|
+
return names
|
|
199
|
+
for w in cast("list[Any]", workflows):
|
|
200
|
+
if not isinstance(w, dict):
|
|
201
|
+
continue
|
|
202
|
+
entry = cast("dict[str, Any]", w)
|
|
203
|
+
w_id = entry.get("name")
|
|
204
|
+
metadata = entry.get("metadata")
|
|
205
|
+
if isinstance(w_id, str) and isinstance(metadata, dict):
|
|
206
|
+
display_name = cast("dict[str, Any]", metadata).get("displayName")
|
|
207
|
+
if isinstance(display_name, str) and display_name:
|
|
208
|
+
names[w_id] = display_name
|
|
209
|
+
return names
|
|
177
210
|
|
|
178
211
|
|
|
179
212
|
@dataclass(frozen=True)
|
|
@@ -185,11 +185,20 @@ class ImageRef:
|
|
|
185
185
|
"""A reference image for I2I, identified by the upload's media UUID.
|
|
186
186
|
|
|
187
187
|
The wire shape is the dict returned by :meth:`to_wire`. The UUID comes
|
|
188
|
-
from a prior ``/v1/flow/uploadImage`` call
|
|
189
|
-
``samples/captured/01_upload_image.json``).
|
|
188
|
+
from a prior ``/v1/flow/uploadImage`` call OR a generated image's media id
|
|
189
|
+
(see ``samples/captured/01_upload_image.json``).
|
|
190
|
+
|
|
191
|
+
``display_name`` and ``local_path`` are UI-automation-only hints (ignored by
|
|
192
|
+
:meth:`to_wire`): they let the transport attach the ref by **selecting the
|
|
193
|
+
already-existing Flow asset in the picker** — located by ``name`` (the media
|
|
194
|
+
UUID) in the tile's image URL, surfaced by ``display_name`` when a search is
|
|
195
|
+
needed — and preferred over re-uploading a duplicate. ``local_path`` is the
|
|
196
|
+
fallback file to upload only when the asset can't be located in place.
|
|
190
197
|
"""
|
|
191
198
|
|
|
192
199
|
name: str
|
|
200
|
+
display_name: str = ""
|
|
201
|
+
local_path: str = ""
|
|
193
202
|
|
|
194
203
|
def __post_init__(self) -> None:
|
|
195
204
|
# Reject empty, whitespace-only, AND whitespace-padded UUIDs.
|
|
@@ -2110,6 +2110,16 @@ class UiAutomationTransport(VideoGenerationMixin):
|
|
|
2110
2110
|
if request.ref_paths:
|
|
2111
2111
|
await self._attach_references(page, list(request.ref_paths), out_dir=out_dir)
|
|
2112
2112
|
|
|
2113
|
+
# Pre-generated image UUID refs: attach by selecting the EXISTING Flow
|
|
2114
|
+
# asset in the reference picker (no duplicate upload — founder principle),
|
|
2115
|
+
# falling back to uploading the local file only when it can't be located.
|
|
2116
|
+
if request.refs:
|
|
2117
|
+
await self._attach_image_uuid_refs(
|
|
2118
|
+
page,
|
|
2119
|
+
[(r.name, r.display_name, r.local_path) for r in request.refs],
|
|
2120
|
+
out_dir=out_dir,
|
|
2121
|
+
)
|
|
2122
|
+
|
|
2113
2123
|
# Entity references: attach locked CHARACTER entities via the Personagens
|
|
2114
2124
|
# picker (inherited from the video transport). The entity must live in the
|
|
2115
2125
|
# project we generate in (pass --project / project_id). Flow's JS then
|