gflow-cli 0.26.0__tar.gz → 0.27.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.26.0 → gflow_cli-0.27.0}/CHANGELOG.md +22 -1
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/PKG-INFO +1 -1
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/INDEX.md +4 -1
- gflow_cli-0.27.0/docs/LIVE_VERIFICATION_v0.27.0.md +100 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/MOVIE.md +70 -3
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/PROJECT_STATUS.md +42 -1
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/schemas/movie-handoff.schema.json +9 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/pyproject.toml +1 -1
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/__init__.py +1 -1
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/cli_movie.py +57 -11
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/composition.py +80 -4
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/movie_manifest.py +92 -4
- gflow_cli-0.27.0/tests/cli/test_movie_manifest_style_variants.py +455 -0
- gflow_cli-0.27.0/tests/composition/test_style_variants.py +272 -0
- gflow_cli-0.27.0/tests/composition/test_style_variants_e2e.py +305 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/uv.lock +1 -1
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/README.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/commands/gflow/active.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/commands/gflow/branch-review.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/commands/gflow/changelog.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/commands/gflow/check.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/commands/gflow/doc-review.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/commands/gflow/issue-assessment.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/commands/gflow/issue-resolve.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/commands/gflow/known-issues.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/commands/gflow/next.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/commands/gflow/plan.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/commands/gflow/pr-council-review.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/commands/gflow/predict.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/commands/gflow/release.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/commands/gflow/scenario.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/commands/gflow/sonar.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.claude/commands/gflow/status.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.env.template +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.gitattributes +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.github/CODEOWNERS +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.github/copilot-instructions.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.github/dependabot.yml +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.github/workflows/ci.yml +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.github/workflows/external-pr-triage.yml +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.github/workflows/governance-advisory.yml +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.github/workflows/governance-benchmark.yml +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.github/workflows/main-base-guard.yml +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.github/workflows/release.yml +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.gitignore +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.gitleaks.toml +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.pre-commit-config.yaml +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/.secrets.baseline +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/AGENTS.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/CLAUDE.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/CONFIGURATION.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/CONTRIBUTING.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/DISCLAIMER.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/GEMINI.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/KNOWN_ISSUES.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/LICENSE +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/PLAN.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/README.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/RELEASE.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/ROADMAP.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/conftest.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docker-compose.yml +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/AGENT_GUIDE.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/AGENT_UI_E2E.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/AGENT_UI_RECON.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/ARCHITECTURE.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/AUTHENTICATION.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/CHARACTER.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/CHARACTER_RECON.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/CONFIGURATION.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/DATA_LAYER.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/DEBUGGING.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/DEMOS.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/DEVELOPMENT.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/E2E_TESTING.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/EXTERNAL_STORAGE.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/GITHUB.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/GOVERNANCE_BENCHMARK.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/IMAGE_UPSCALE_RECON.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_data_layer.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_image_batch.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.10.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.11.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.12.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.13.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.16.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.17.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.18.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.19.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.20.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.20.1.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.21.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.22.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.23.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.24.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.25.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.26.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.7.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.8.1.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.9.0.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_v0.9.1.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/LIVE_VERIFICATION_video_download.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/MCP.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/PROMPT_EXPANSION.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/SECURITY.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/TOOLS.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/USAGE.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/USER_GUIDE.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/assets/demo-split-pf.gif +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/assets/example-run.gif +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/assets/examples.webp +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/medium_tutorial.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/sonar-cleanup-tracker.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/superpowers/plans/2026-06-12-issue-174-library-ui-attach/PLAN.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/superpowers/plans/2026-06-22-mcp-server/PLAN.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/superpowers/plans/2026-06-22-mcp-server/PREDICT.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/superpowers/plans/2026-06-22-mcp-server/SCENARIO.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/superpowers/plans/2026-06-22-prompt-expansion/PLAN.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/superpowers/plans/2026-06-22-prompt-expansion/PREDICT.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/superpowers/plans/2026-06-22-prompt-expansion/SCENARIO.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/superpowers/plans/2026-06-24-gflow-studio-scaffold/PLAN.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/superpowers/plans/2026-06-24-rest-api-layer/PLAN.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/superpowers/plans/2026-06-26-mcp-e2e-test/PLAN.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/superpowers/research/2026-06-27-tool-abstraction-evaluation.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/docs/superpowers/specs/2026-06-29-issue-assessment-workflow-design.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/examples/README.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/examples/batch_from_config.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/examples/multi_prompt_t2i.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/examples/sample_config.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/examples/sample_prompts.txt +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/examples/single_image_t2i.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/examples/workflow_chain.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/llms.txt +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/samples/README.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/samples/captured/01_upload_image.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/samples/captured/02_batchAsyncGenerateVideoText.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/samples/captured/04_archive_workflow.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/samples/captured/05_createProject.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/samples/captured/06_batchGenerateImages.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/samples/captured/07_batchGenerateImages_seeded.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/samples/captured/08_batchAsyncGenerateVideoStartAndEndImage.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/samples/captured/09_batchAsyncGenerateVideoReferenceImages.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/samples/captured/10_batchCheckAsyncVideoGenerationStatus_successful.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/samples/captured/11_batchCheckAsyncVideoGenerationStatus_failed.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/samples/captured/12_create_scene.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/samples/captured/13_sceneWorkflows_update.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/samples/captured/14_get_scene_workflows.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/samples/captured/15_commit_flowWorkflow.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/ci/check_doc_links.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/ci/check_materiality.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/ci/check_repo_hygiene.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/debug_editor.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/debug_gen_settings.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/debug_settings.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/_recording_client.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/_spike_common.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/active_plan.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/analyze_agent_ui_capture.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/capture_i2v_frame_slots_dom.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/capture_i2v_intercept_submit.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/capture_i2v_model_select_repro.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/capture_i2v_post_bind_state.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/capture_image_add_media_dom.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/capture_locale_invariants.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/cdp_drive_and_probe.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/character_create_spike.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/character_create_spike_v2.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/dump_character_selectors.js +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/make_project.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/materiality_backtest.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/monitor_pr_38.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/patch_character.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/skillopt/README.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/skillopt/harness.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/skillopt/tasks.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/spike_char_editor_dom.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/spike_char_gen_capture.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/spike_image_upscale_capture.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/spike_image_upscale_drive.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/spike_image_upscale_recaptcha_action.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/spike_image_upscale_rest_probe.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/spike_issue170_picker_locale_recon.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/spike_issue174_library_ui_recon.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/spike_movie_attach_payload.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/spike_movie_entity_recon.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/spike_movie_gen_capture.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/spike_movie_picker_select.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/spike_movie_voice_list.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/spike_patch_entity.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/dev/spike_patchright.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/diag/README.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/diag/capture_flow_traffic.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/diag/memory_profile.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/diag/recaptcha_mint.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/e2e/agentic_image_e2e.ps1 +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/e2e/capture_agent_toggle.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/record_demo.ps1 +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/smoke_image.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/smoke_real_chrome_image.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/smoke_video_editor.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/smoke_worker_style.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/scripts/verify_chrome_auth_viability.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/skills/README.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/skills/gflow-cli/SKILL.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/skills/issue-assessment/SKILL.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/skills/issue-resolve/SKILL.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/skills/plan/SKILL.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/skills/pr-council-review/SKILL.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/skills/predict/SKILL.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/skills/scenario/SKILL.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/skills/status/SKILL.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/sonar-project.properties +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/__main__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/_cli_helpers.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/_engine.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/_retry.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/_sapisidhash.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/character.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/client.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/dto.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/image.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/image_upscale.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/recaptcha.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/routes.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/scene.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/transports/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/transports/_common.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/transports/_fingerprint.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/transports/base.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/transports/drivers/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/transports/drivers/agentic.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/transports/drivers/base.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/transports/drivers/classic.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/transports/drivers/factory.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/transports/experimental/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/transports/experimental/bearer.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/transports/experimental/evaluate_fetch.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/transports/experimental/sapisidhash.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/transports/ui_automation.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/transports/ui_automation_video.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/api/video.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/auth/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/auth/base.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/auth/cookies.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/auth/factory.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/auth/internal_chromium.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/auth/real_chrome.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/auth/strategies.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/auth/verification.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/browser_manager.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/chain.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/chain_manifest.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/cli.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/cli_character.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/cli_data.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/cli_image.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/cli_models.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/cli_run.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/cli_scene.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/cli_tools.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/cli_video.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/config.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/chain_repo.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/migrations/0001_initial.sql +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/migrations/0002_add_cloud_storage.sql +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/migrations/0003_add_scene_tables.sql +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/migrations/0004_add_scene_output_path.sql +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/migrations/0005_add_chain_links.sql +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/migrations/0006_add_operations_metadata.sql +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/migrations/0007_queue.sql +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/migrations/0008_add_operation_expanded_prompt.sql +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/migrations/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/models.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/queries.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/recorder.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/redaction.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/repository.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/data/store.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/errors.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/exceptions.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/image_batch.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/json_output.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/manifest.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/mcp/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/mcp/prompts.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/mcp/resources.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/mcp/server.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/mcp/tools.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/media.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/observability.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/paths.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/profile_store.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/services/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/services/character_create.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/storage.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/tools/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/tools/banned.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/tools/builtin/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/tools/builtin/creative-director.toml +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/tools/expander.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/tools/invocation.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/tools/loader.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/tools/registry.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/tools/runtime.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/tools/spec.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/ui/app.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/ui/server.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/worker/daemon.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/src/gflow_cli/worker/queue.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tasks/lessons.md +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/test_assets/sample_batch.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/test_assets/sample_batch.tsv +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/test_assets/sample_batch_invalid.tsv +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/fixtures/character_gen_response.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/fixtures/patch_entity_response.json +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_aisandbox_auth_error.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_aisandbox_auth_headers.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_bearer_redaction.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_character.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_client.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_client_character.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_client_delete_characters.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_client_generate_character.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_client_image.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_client_launch_kwargs.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_client_patch_entity.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_client_scene.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_client_upscale.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_concurrency.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_dto.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_engine.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_image.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_image_dto.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_image_upscale.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_post_json_aisandbox_auth.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_recaptcha.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_retry.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_routes.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_routes_character.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_routes_scene.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_sapisidhash_helper.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_scene_models.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_video.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/test_video_request.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/conftest.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/drivers/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/drivers/test_agentic.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/drivers/test_factory.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/test_base.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/test_bearer.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/test_common.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/test_evaluate_fetch.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/test_factory.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/test_fingerprint.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/test_sapisidhash.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/test_transport_timeout.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/test_ui_automation.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/test_ui_automation_batch.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/test_ui_automation_image_mode.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/test_ui_automation_video.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/api/transports/test_ui_character_editor.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/auth/strategies/test_factory.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/auth/strategies/test_strategies.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/auth/test_cookies.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/auth/test_verification.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_cli_auth_list.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_cli_character.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_cli_character_create.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_cli_data.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_cli_image.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_cli_image_seed_removed.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_cli_image_selector_drift.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_cli_image_upscale.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_cli_models.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_cli_movie.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_cli_run.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_cli_scene.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_cli_tools.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_cli_video.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_cli_video_chain.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_error_handling.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_helpers.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_movie_manifest.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_settings_validation.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/cli/test_t2i_multi_prompt.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/composition/test_character.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/composition/test_compose_prompt.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/composition/test_handoff.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/conftest.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/data/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/data/test_chain_repo.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/data/test_find_incomplete_character.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/data/test_models.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/data/test_packaging.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/data/test_recorder.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/data/test_recorder_character.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/data/test_redaction.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/data/test_repository.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/data/test_scene_persistence.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/data/test_settings_and_errors.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/data/test_store_migrations.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/dev/test_recording_client.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/conftest.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/test_aisandbox_auth_live.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/test_auth_verification_e2e.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/test_chain_e2e.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/test_character_create_e2e.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/test_daemon_e2e.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/test_data_layer_e2e.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/test_i2v_flags_e2e.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/test_image_batch_e2e.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/test_image_i2i_ref_cap_e2e.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/test_json_output_e2e.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/test_locale_selectors_e2e.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/test_scene_compose_live.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/test_tools_e2e.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/test_transports_e2e.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/test_video_r2v_ref_cap_e2e.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/e2e/test_video_t2v_e2e.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/auth.feature +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/auth_login.feature +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/character_create.feature +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/character_read.feature +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/conftest.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/image.feature +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/image_upscale.feature +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/locale_picker_include.feature +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/test_auth_login_steps.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/test_auth_steps.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/test_character_create_steps.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/test_character_read_steps.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/test_image_steps.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/test_image_upscale_steps.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/test_locale_picker_include_steps.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/test_step_collision_guard.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/test_video_agent_ui_steps.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/test_video_chain_steps.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/video_agent_ui.feature +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/features/video_chain.feature +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/fixtures/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/fixtures/seeded_catalog.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/image_batch/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/image_batch/test_image_manifest.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/image_batch/test_observability_events.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/integration/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/integration/conftest.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/integration/constants.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/integration/test_storage_gcs.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/integration/test_storage_s3.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/mcp/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/mcp/conftest.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/mcp/test_server.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/mcp/test_stdio_transport.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/mcp/test_tools_helpers.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/mcp/test_tools_wired.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/scripts/test_analyze_agent_ui_capture.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/scripts/test_capture_locale_invariants.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/scripts/test_check_materiality.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/scripts/test_check_repo_hygiene.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/scripts/test_materiality_backtest.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/services/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/services/test_character_create_redaction.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/services/test_character_create_saga.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/services/test_character_gen_no_direct_post.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/smoke/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/smoke/test_profile_account_smoke.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/smoke/test_real_flow.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_auth.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_browser_manager.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_chain.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_chain_manifest.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_cli_data.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_config.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_conftest_isolation.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_data_queries.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_documentation_gate.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_errors.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_errors_403.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_json_output.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_manifest.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_marker_registry.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_media.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_observability.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_paths.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_profile_store.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/test_smoke.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/tools/__init__.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/tools/test_banned.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/tools/test_expander.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/tools/test_invocation.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/tools/test_loader.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/tools/test_registry.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/tools/test_runtime.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/tools/test_spec.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/ui/test_app.py +0 -0
- {gflow_cli-0.26.0 → gflow_cli-0.27.0}/tests/worker/test_daemon.py +0 -0
|
@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.27.0] — 2026-07-07
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Global `[style]` block with named variants in `movie.toml` (Issue #239):** channel-format
|
|
15
|
+
videos can now express a visual style system (e.g. monochrome → warm color arc) once in the
|
|
16
|
+
`[style]` block and select it per-scene via `style_variant`, without repeating style text in
|
|
17
|
+
every scene's action. Adds `prefix`/`suffix` fields to `[style]`, `[style.variants.*]`
|
|
18
|
+
sub-tables, per-scene `style_variant` and `style_suffix` fields, deterministic composition
|
|
19
|
+
rule, and `style_applied` (variant/prefix/suffix/scene_suffix) per clip in the handoff
|
|
20
|
+
manifest. `none` is a reserved variant name (opt-out keyword) and may not be defined.
|
|
21
|
+
- **Prompt-aware resume for `movie run`:** completed scenes now persist a SHA-256 hash of
|
|
22
|
+
their composed prompt (`style_hash`); on resume, a scene whose prompt changed (style edit,
|
|
23
|
+
variant switch, action tweak) is regenerated instead of silently skipped. Unchanged scenes
|
|
24
|
+
still cost nothing. Old state files fall back to comparing the stored prompt text and are
|
|
25
|
+
never re-run on a guess. Dry-run shows the resolved style per scene and marks stale scenes
|
|
26
|
+
as `re-run (style changed)`.
|
|
27
|
+
|
|
10
28
|
## [0.26.0] — 2026-07-06
|
|
11
29
|
|
|
12
30
|
### Added
|
|
@@ -1812,7 +1830,10 @@ shell-script template that branches on these codes.
|
|
|
1812
1830
|
|
|
1813
1831
|
First skeleton. Not functional end-to-end yet.
|
|
1814
1832
|
|
|
1815
|
-
[Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.
|
|
1833
|
+
[Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.27.0...HEAD
|
|
1834
|
+
[0.27.0]: https://github.com/ffroliva/gflow-cli/compare/v0.26.0...v0.27.0
|
|
1835
|
+
[0.26.0]: https://github.com/ffroliva/gflow-cli/compare/v0.25.0...v0.26.0
|
|
1836
|
+
[0.25.0]: https://github.com/ffroliva/gflow-cli/compare/v0.24.0...v0.25.0
|
|
1816
1837
|
[0.24.0]: https://github.com/ffroliva/gflow-cli/compare/v0.23.0...v0.24.0
|
|
1817
1838
|
[0.23.0]: https://github.com/ffroliva/gflow-cli/compare/v0.22.0...v0.23.0
|
|
1818
1839
|
[0.22.0]: https://github.com/ffroliva/gflow-cli/compare/v0.21.0...v0.22.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gflow-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.27.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
|
|
@@ -22,7 +22,10 @@ Welcome to the `gflow-cli` documentation. This index is the routing layer: it te
|
|
|
22
22
|
| [CONTRIBUTING](../CONTRIBUTING.md) | TDD workflow, test categories, coverage targets | Before opening a PR |
|
|
23
23
|
| **[docs/DEVELOPMENT.md](DEVELOPMENT.md)** | Branching model, PR protocol, e2e gate, version bump protocol, AI-assisted workflow | Understanding the end-to-end dev process |
|
|
24
24
|
| **[docs/E2E_TESTING.md](E2E_TESTING.md)** | Layer model, cost sub-markers, run commands, isolation patterns, roadmap to contract/replay layer | Running or extending e2e tests; cost control |
|
|
25
|
+
| **[docs/AGENT_UI_E2E.md](AGENT_UI_E2E.md)** | Deterministic e2e runbook for the Agentic UI image path (force-agent trigger, validation ledger) | Live-verifying Agentic-UI features |
|
|
25
26
|
| **[docs/GITHUB.md](GITHUB.md)** | Maintainer PR triage protocol, forked PR handling, SonarCloud scenarios | Reviewing or merging a GitHub PR |
|
|
27
|
+
| [docs/sonar-cleanup-tracker.md](sonar-cleanup-tracker.md) | SonarCloud zero-smells cleanup tracker (`chore/sonar-zero-cleanup`) | Resuming or auditing the Sonar cleanup effort |
|
|
28
|
+
| [docs/medium_tutorial.md](medium_tutorial.md) | Long-form tutorial article (Medium draft): Veo + Imagen from the terminal | Writing or updating outreach/tutorial content |
|
|
26
29
|
| [.env.template](../.env.template) | All environment variables with defaults | Setting up a new shell or container |
|
|
27
30
|
| **[docs/AUTHENTICATION.md](AUTHENTICATION.md)** | Full auth flow, session storage, multi-account, refresh | First `gflow auth login`, or auth errors |
|
|
28
31
|
| **[docs/CONFIGURATION.md](CONFIGURATION.md)** | All env vars, precedence chain, default paths per OS | Tuning behaviour, picking output paths |
|
|
@@ -117,7 +120,7 @@ Slash commands for Claude Code, stored in `.claude/commands/gflow/`. All prefixe
|
|
|
117
120
|
**"A gflow command hangs / fails — where do I start?"** → [DEBUGGING § Quick reference](DEBUGGING.md#quick-reference)
|
|
118
121
|
**"Flow's UI broke a selector — how do I diagnose it?"** → [DEBUGGING § Inspecting Flow's live UI](DEBUGGING.md#inspecting-flows-live-ui)
|
|
119
122
|
**"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.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)
|
|
123
|
+
**"What was actually live-verified for the latest release?"** → latest: [LIVE_VERIFICATION_v0.27.0](LIVE_VERIFICATION_v0.27.0.md) (**`[style]` block with named variants + prompt-aware resume — credit-free CLI verification**: real `movie run --dry-run` 3-way ledger proving resolved-style display, `skip (done)` on matching `style_hash`, and `re-run (style changed)` after a style edit; composition is local, wire path untouched, so no Veo credits spent — first credited styled run will confirm visually). Prior: [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
124
|
**"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
125
|
**"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
126
|
**"What was live-verified for the video-download feature (#29)?"** → [LIVE_VERIFICATION_video_download](LIVE_VERIFICATION_video_download.md)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Live Verification — v0.27.0
|
|
2
|
+
|
|
3
|
+
Release date: 2026-07-07. Headline: **global `[style]` block with named variants
|
|
4
|
+
in `movie.toml`** (Issue #239, PR #259) — express a visual style arc once
|
|
5
|
+
(prefix/suffix + `[style.variants.*]`) and select it per-scene via
|
|
6
|
+
`style_variant` / `style_suffix` — plus **prompt-aware resume** for `movie run`
|
|
7
|
+
(completed scenes persist a `style_hash`; a scene whose composed prompt changed
|
|
8
|
+
is regenerated instead of silently skipped).
|
|
9
|
+
|
|
10
|
+
Verification run: 2026-07-07, real CLI (`gflow movie run --dry-run`), Windows,
|
|
11
|
+
`.venv` build of the release tree. **Deliberately credit-free**: this release is
|
|
12
|
+
pure local prompt composition + state logic — the Flow wire path (transports,
|
|
13
|
+
selectors, auth) is untouched, so no live Veo generation was spent. The dry-run
|
|
14
|
+
path exercises the identical manifest→parse→compose→resume-decision pipeline the
|
|
15
|
+
live run uses; only `_generate_scene` (unchanged this release) is skipped.
|
|
16
|
+
|
|
17
|
+
## Scope
|
|
18
|
+
|
|
19
|
+
| Change | Surface | Verdict |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `[style]` prefix/suffix + `[style.variants.*]`, per-scene `style_variant`/`style_suffix` | `composition.py`, `movie_manifest.py` | ✅ CLI dry-run + 91 unit/integration tests |
|
|
22
|
+
| Prompt-aware resume (`style_hash`, `is_stale_for`, re-run on style edit) | `movie_manifest.py`, `cli_movie.py` | ✅ CLI dry-run 3-way ledger (below) |
|
|
23
|
+
| Dry-run shows resolved style + stale marker | `cli_movie.py` | ✅ CLI dry-run output |
|
|
24
|
+
| `style_applied` (variant/prefix/suffix/scene_suffix) per clip + schema | `composition.py`, `docs/schemas/movie-handoff.schema.json` | ✅ Unit-tested (jsonschema validation) |
|
|
25
|
+
| Reserved `none` variant name, strict variant parsing | `movie_manifest.py` | ✅ Unit-tested (ConfigurationError paths) |
|
|
26
|
+
|
|
27
|
+
## Evidence ledger (credit-free CLI runs)
|
|
28
|
+
|
|
29
|
+
Manifest: 3 scenes — `s1-base` (base style), `s2-warm` (`style_variant="warm"` +
|
|
30
|
+
`style_suffix="golden hour light"`), `s3-optout` (`style_variant="none"`), with
|
|
31
|
+
`prefix = "SCENE:"` and a base suffix.
|
|
32
|
+
|
|
33
|
+
1. **Composed prompt (canonical order)** — `compose_prompt` for `s1-base`
|
|
34
|
+
produced exactly:
|
|
35
|
+
`SCENE: Walks through a rainy plaza. Wide shot. Black and white cinematic
|
|
36
|
+
street photography, film grain.` — prefix first, sentence-composed
|
|
37
|
+
action/framing, raw base suffix last.
|
|
38
|
+
2. **Run 1 (fresh state)** — plan shows the resolved style per scene and full
|
|
39
|
+
cost: `s1-base … style=base 1 credit(s)`, `s2-warm … style=warm
|
|
40
|
+
+style_suffix 1 credit(s)`, `s3-optout … style=none 1 credit(s)`,
|
|
41
|
+
`Estimated credits: ~3`.
|
|
42
|
+
3. **Run 2 (s1 completed in `movie-state.json` with matching `style_hash`)** —
|
|
43
|
+
`s1-base … skip (done)`, `Estimated credits: ~2`. State file JSON carries
|
|
44
|
+
`"style_hash": "<sha256 of the composed prompt>"` (round-tripped via
|
|
45
|
+
`MovieState.save`/`load`).
|
|
46
|
+
4. **Run 3 (base suffix edited to "Sepia archival newsreel look.")** —
|
|
47
|
+
`s1-base … re-run (style changed) 1 credit(s)`, `Estimated credits: ~3`.
|
|
48
|
+
The stale scene is regenerated; the unchanged `s2-warm`/`s3-optout`
|
|
49
|
+
decisions are unaffected. This is the exact staleness bug the feature
|
|
50
|
+
exists to prevent (stale clip silently skipped after a style edit).
|
|
51
|
+
5. **User-confirmable artifact** — the three plan outputs above are
|
|
52
|
+
reproducible with any manifest; the same decision logic drives the real run
|
|
53
|
+
loop (`_run_movie` calls the identical `is_stale_for` check before spending
|
|
54
|
+
credits).
|
|
55
|
+
|
|
56
|
+
### Not live-verified this cycle (recorded, not omitted)
|
|
57
|
+
|
|
58
|
+
Actual Veo generation with a style-suffixed prompt (i.e. confirming Flow's
|
|
59
|
+
model renders the requested grade) was **not** exercised — it costs 20 credits
|
|
60
|
+
per scene and the prompt text demonstrably reaches the existing, unchanged
|
|
61
|
+
generation path (`_run_one_scene` passes the same `compose_prompt` output that
|
|
62
|
+
v0.26.0 passed). First credited `movie run` on a styled manifest will confirm
|
|
63
|
+
visually; no code path is untested locally.
|
|
64
|
+
|
|
65
|
+
### Pre-existing display nit (not this release)
|
|
66
|
+
|
|
67
|
+
The plan line's `[t2v]`/`[r2v]` mode tag is swallowed by rich markup
|
|
68
|
+
(`console.print` interprets `[t2v]` as a style tag) — present on `develop`
|
|
69
|
+
before PR #259; cosmetic; tracked as a follow-up.
|
|
70
|
+
|
|
71
|
+
## Pre-tag gates
|
|
72
|
+
|
|
73
|
+
- `/gflow:check`: hygiene ✅ · ruff ✅ (no rewrites) · pyright `0 errors` ✅ ·
|
|
74
|
+
full suite 2054 passed / 7 skipped ✅ (local), 3.11/3.12/3.13 matrix +
|
|
75
|
+
SonarCloud quality gate ✅ on PR #259 (same tree).
|
|
76
|
+
- `/code-review` (independent, 8-angle): 10 findings — all fixed in
|
|
77
|
+
`61a9887` before merge.
|
|
78
|
+
- `/gflow:doc-review`: mechanical pass UPDATED×2 (PROJECT_STATUS current
|
|
79
|
+
release was stale at v0.24.0 — v0.25.0/v0.26.0/v0.27.0 entries added; 3 docs
|
|
80
|
+
added to INDEX), links 23/23 green. Council verdict: **GREEN/YELLOW/YELLOW**
|
|
81
|
+
across 3 auditors — 1 Tier-1 finding (this doc overclaimed "91
|
|
82
|
+
style-variants tests"; actual collection is 59 — fixed in the release-prep
|
|
83
|
+
commit), Tier-2 fixed (stale MOVIE.md "active development" banner), Tier-3
|
|
84
|
+
deferred (hardcoded `build_handoff` `generator.version="0.14.0"`; MOVIE.md
|
|
85
|
+
error-path doc anchor; USAGE.md movie coverage). Council reports at
|
|
86
|
+
`tmp/council/0{1,2,3}-*.md` (local-only).
|
|
87
|
+
|
|
88
|
+
## Post-tag evidence
|
|
89
|
+
|
|
90
|
+
*(filled after the v0.27.0 tag push / publish)*
|
|
91
|
+
|
|
92
|
+
## Automated coverage
|
|
93
|
+
|
|
94
|
+
- 59 style-variants tests across `tests/composition/test_style_variants.py`,
|
|
95
|
+
`test_style_variants_e2e.py`, `tests/cli/test_movie_manifest_style_variants.py`
|
|
96
|
+
(composition order, variant resolution, reserved `none`, strict parsing,
|
|
97
|
+
`style_applied` + jsonschema validation, `resume_hash` properties,
|
|
98
|
+
`is_stale_for` all four branches, state round-trip).
|
|
99
|
+
- Full suite green: 2054 passed, 7 skipped (local) and 3.11/3.12/3.13 matrix +
|
|
100
|
+
SonarCloud quality gate green on PR #259. `pyright src` 0 errors, ruff clean.
|
|
@@ -5,9 +5,9 @@ clips that share the **same characters** (face + voice) across every scene. It
|
|
|
5
5
|
is the orchestration layer on top of `gflow character` (entity creation) and
|
|
6
6
|
`gflow video` (R2V generation).
|
|
7
7
|
|
|
8
|
-
> Status:
|
|
9
|
-
>
|
|
10
|
-
>
|
|
8
|
+
> Status: shipped (since v0.14.0) and evolving. The CLI surface below is
|
|
9
|
+
> release-stable per SemVer; alpha (`0.x`) minor versions may still extend or
|
|
10
|
+
> adjust it, with changes noted in the CHANGELOG.
|
|
11
11
|
|
|
12
12
|
## Quick start
|
|
13
13
|
|
|
@@ -31,6 +31,18 @@ title = "E2E Stickman"
|
|
|
31
31
|
project = "6ba50219-…" # reusable Flow project id
|
|
32
32
|
output_dir = "./out"
|
|
33
33
|
|
|
34
|
+
[style]
|
|
35
|
+
look = "cinematic, shallow depth of field"
|
|
36
|
+
palette = "warm golden tones"
|
|
37
|
+
negative = "no text, no watermark"
|
|
38
|
+
suffix = "Black and white cinematic street photography, photorealistic, film grain."
|
|
39
|
+
|
|
40
|
+
[style.variants.warm]
|
|
41
|
+
suffix = "Warm golden-hour cinematic grade."
|
|
42
|
+
|
|
43
|
+
[style.variants.cool]
|
|
44
|
+
suffix = "Cool blue-toned cinematic grade."
|
|
45
|
+
|
|
34
46
|
[[characters]]
|
|
35
47
|
name = "Stickman"
|
|
36
48
|
identity = "entity" # reuse a Flow CHARACTER entity across scenes
|
|
@@ -47,6 +59,14 @@ line = "We finally made it to the top!"
|
|
|
47
59
|
aspect = "9:16"
|
|
48
60
|
model = "veo-lite"
|
|
49
61
|
duration = 8
|
|
62
|
+
|
|
63
|
+
[[scenes]]
|
|
64
|
+
id = "close-up"
|
|
65
|
+
action = "smiles with excitement"
|
|
66
|
+
style_variant = "warm" # selects [style.variants.warm]
|
|
67
|
+
style_suffix = "golden hour light" # appended after the variant suffix
|
|
68
|
+
aspect = "9:16"
|
|
69
|
+
duration = 6
|
|
50
70
|
```
|
|
51
71
|
|
|
52
72
|
On first run, characters with `identity = "entity"` are created once (image
|
|
@@ -54,6 +74,53 @@ generation — **free**, no credits) and cached. Each scene then generates a cli
|
|
|
54
74
|
that **reuses the same Flow CHARACTER entity** so the character drives every
|
|
55
75
|
scene from one identity.
|
|
56
76
|
|
|
77
|
+
### Style variants
|
|
78
|
+
|
|
79
|
+
The `[style]` block defines a **global visual style** applied to every scene.
|
|
80
|
+
For channel-format videos where the style changes across scenes (e.g. a
|
|
81
|
+
monochrome → warm color arc), use **named variants**:
|
|
82
|
+
|
|
83
|
+
```toml
|
|
84
|
+
[style]
|
|
85
|
+
prefix = "" # optional, prepended before the composed scene text
|
|
86
|
+
suffix = "Black and white cinematic street photography, photorealistic, film grain."
|
|
87
|
+
|
|
88
|
+
[style.variants.warm]
|
|
89
|
+
suffix = "Warm golden-hour cinematic grade."
|
|
90
|
+
|
|
91
|
+
[style.variants.cool]
|
|
92
|
+
suffix = "Cool blue-toned cinematic grade."
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Per-scene selection:
|
|
96
|
+
|
|
97
|
+
| Field | Effect |
|
|
98
|
+
|---|---|
|
|
99
|
+
| `style_variant = "warm"` | Selects `[style.variants.warm]` — its `suffix` replaces the base `suffix`. |
|
|
100
|
+
| `style_variant = "none"` | Opts out of all style suffixes (base + variant). Prefix is still applied. |
|
|
101
|
+
| *(omitted)* | Uses the base `[style]` suffix. |
|
|
102
|
+
| `style_suffix = "sunset light"` | Scene-specific text appended **after** the variant/base suffix. |
|
|
103
|
+
|
|
104
|
+
`none` is a **reserved name**: defining `[style.variants.none]` is a
|
|
105
|
+
configuration error, so the opt-out keyword can never shadow a real variant.
|
|
106
|
+
|
|
107
|
+
**Composition rule** (deterministic, no LLM):
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
final_prompt = [prefix] + composed_scene_text + [variant.suffix | base.suffix] + [scene.style_suffix]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The applied style is recorded per clip in `<manifest>-handoff.json` as
|
|
114
|
+
`style_applied` (`variant`, `prefix`, `suffix`, `scene_suffix`), so downstream
|
|
115
|
+
tools (Remotion, editors) can introspect it.
|
|
116
|
+
|
|
117
|
+
**Resume:** each completed scene's state records a hash of its composed
|
|
118
|
+
prompt. If you edit the style (or anything else that changes a scene's
|
|
119
|
+
prompt) and re-run, only the affected scenes are regenerated — unchanged
|
|
120
|
+
scenes are still skipped and cost no credits. State files written by older
|
|
121
|
+
gflow-cli versions fall back to comparing the stored prompt text; scenes with
|
|
122
|
+
no stored prompt are never re-run automatically.
|
|
123
|
+
|
|
57
124
|
> **Consistency is best-effort, not pixel-exact.** gflow guarantees the *right
|
|
58
125
|
> entity rides the wire* (`consistency_method = entity`); the final on-screen
|
|
59
126
|
> fidelity is Flow's Veo R2V model, which may reinterpret minimalist or
|
|
@@ -4,6 +4,43 @@
|
|
|
4
4
|
|
|
5
5
|
## Current release
|
|
6
6
|
|
|
7
|
+
**v0.27.0 — alpha.** **Global `[style]` block with named variants + prompt-aware resume
|
|
8
|
+
for `gflow movie` (#239).** A `movie.toml` can now express a visual style system once —
|
|
9
|
+
`prefix`/`suffix` on `[style]` plus `[style.variants.*]` sub-tables — and select it
|
|
10
|
+
per-scene via `style_variant` / `style_suffix` (deterministic composition, `none`
|
|
11
|
+
reserved as the opt-out keyword). The handoff manifest records `style_applied`
|
|
12
|
+
(variant/prefix/suffix/scene_suffix) per clip. Resume is now prompt-aware: completed
|
|
13
|
+
scenes persist a `style_hash`; a scene whose composed prompt changed is regenerated
|
|
14
|
+
instead of silently skipped, and dry-run marks it `re-run (style changed)`. Carries
|
|
15
|
+
forward v0.26.0 (i2i select-in-place by UUID). Verification:
|
|
16
|
+
[LIVE_VERIFICATION_v0.27.0](LIVE_VERIFICATION_v0.27.0.md) (credit-free CLI ledger).
|
|
17
|
+
|
|
18
|
+
**Develop (unreleased, post-v0.27.0):** *(empty — develop is the staging branch for the next release).*
|
|
19
|
+
|
|
20
|
+
<details><summary>v0.26.0 — image i2i references a generated image by UUID (select in place)</summary>
|
|
21
|
+
|
|
22
|
+
**v0.26.0 — alpha.** **Reference a generated image in `image i2i` by its Flow UUID.**
|
|
23
|
+
A `reference_images` entry that is a media UUID is attached by **selecting the
|
|
24
|
+
already-existing asset in Flow's reference picker** (located by UUID in the thumbnail
|
|
25
|
+
URL, surfaced by display-name search when hidden) — no duplicate upload; local upload
|
|
26
|
+
remains the fallback. Generated images also record their Flow `display_name` (credited
|
|
27
|
+
@C1ph3r404). Verification: [LIVE_VERIFICATION_v0.26.0](LIVE_VERIFICATION_v0.26.0.md)
|
|
28
|
+
(live e2e GREEN).
|
|
29
|
+
|
|
30
|
+
</details>
|
|
31
|
+
|
|
32
|
+
<details><summary>v0.25.0 — remote-UUID i2v + silent-failure guards</summary>
|
|
33
|
+
|
|
34
|
+
**v0.25.0 — alpha.** **`video i2v` from a generated image's UUID proven live (#237)** —
|
|
35
|
+
the picker-search attach was reworked to a local-upload path, producing a real 8s
|
|
36
|
+
interpolation from a catalogued UUID. Home-`.env` config matrix (#240) verified live.
|
|
37
|
+
Two silent failures made loud: video-as-image download rejection and rejected-upload
|
|
38
|
+
fail-fast. Verification: [LIVE_VERIFICATION_v0.25.0](LIVE_VERIFICATION_v0.25.0.md).
|
|
39
|
+
|
|
40
|
+
</details>
|
|
41
|
+
|
|
42
|
+
<details><summary>v0.24.0 — `--project` parity across CLI + MCP</summary>
|
|
43
|
+
|
|
7
44
|
**v0.24.0 — alpha.** **`--project` parity across CLI + MCP.** The video commands
|
|
8
45
|
(`video t2v`/`i2v`/`r2v`) gain `--project <id>` to generate into an existing Flow project
|
|
9
46
|
instead of a scratch one (#233/#234), matching `image t2i`/`i2i`; and the MCP
|
|
@@ -13,7 +50,7 @@ capability (`payload["project_id"]`) and validate the id identically. Carries fo
|
|
|
13
50
|
v0.23.0 (MCP generation live + macOS 401 fix). Verification:
|
|
14
51
|
[LIVE_VERIFICATION_v0.24.0](LIVE_VERIFICATION_v0.24.0.md).
|
|
15
52
|
|
|
16
|
-
|
|
53
|
+
</details>
|
|
17
54
|
|
|
18
55
|
<details><summary>v0.23.0 — MCP generation live + macOS 401 fixed</summary>
|
|
19
56
|
|
|
@@ -99,6 +136,10 @@ reporter-verified e2e on macOS).
|
|
|
99
136
|
| Tools framework: `gflow tools` group + `--tool` + `creative-director` + "My Tools" + MCP parity | ✅ done (v0.22.0) |
|
|
100
137
|
| MCP generation wired to FlowWorker (tool→queue→download→record) + `tools` applied + i2v/r2v boundary validation | ✅ done (v0.23.0) |
|
|
101
138
|
| macOS generation 401 fixed — `/fx` cookie-path read + headed-context seed (#222/#230) | ✅ done (v0.23.0) |
|
|
139
|
+
| `--project <id>` on `video t2v/i2v/r2v` + MCP `project` parameter (#233/#234/#235) | ✅ done (v0.24.0) |
|
|
140
|
+
| `video i2v` from a generated image's UUID (#237) + home-`.env` matrix (#240) + silent-failure guards | ✅ done (v0.25.0) |
|
|
141
|
+
| `image i2i` references a generated image by UUID — select in place, no duplicate upload + `display_name` capture | ✅ done (v0.26.0) |
|
|
142
|
+
| `movie.toml` `[style]` block with named variants + prompt-aware resume (`style_hash`) (#239) | ✅ done (v0.27.0) |
|
|
102
143
|
| `gflow video batch` (TSV manifest) on `ui_automation` | ⏳ Phase B |
|
|
103
144
|
| Persistence layer (stay-mounted batch sessions across project boundaries) | ⏳ Phase B |
|
|
104
145
|
| Provider abstraction for official Veo 3.1 API | ⏳ planned |
|
|
@@ -50,6 +50,15 @@
|
|
|
50
50
|
"dialogue": { "type": "array" },
|
|
51
51
|
"prompt": { "type": ["string", "null"] },
|
|
52
52
|
"status": { "enum": ["completed", "failed"] },
|
|
53
|
+
"style_applied": {
|
|
54
|
+
"type": "object",
|
|
55
|
+
"properties": {
|
|
56
|
+
"variant": { "type": ["string", "null"] },
|
|
57
|
+
"prefix": { "type": ["string", "null"] },
|
|
58
|
+
"suffix": { "type": ["string", "null"] },
|
|
59
|
+
"scene_suffix": { "type": ["string", "null"] }
|
|
60
|
+
}
|
|
61
|
+
},
|
|
53
62
|
"x_gflow": { "type": "object" }
|
|
54
63
|
}
|
|
55
64
|
}
|
|
@@ -35,7 +35,14 @@ from gflow_cli._cli_helpers import _make_provider_dir, _resolve_profile, run_wit
|
|
|
35
35
|
from gflow_cli.api.character import CharacterImageRequest
|
|
36
36
|
from gflow_cli.api.client import FlowApiClient
|
|
37
37
|
from gflow_cli.api.video import Aspect, GenerateVideoRequest, Mode, VideoModel, VideoStarted
|
|
38
|
-
from gflow_cli.composition import
|
|
38
|
+
from gflow_cli.composition import (
|
|
39
|
+
Character,
|
|
40
|
+
Scene,
|
|
41
|
+
StyleSpec,
|
|
42
|
+
build_handoff,
|
|
43
|
+
compose_prompt,
|
|
44
|
+
resume_hash,
|
|
45
|
+
)
|
|
39
46
|
from gflow_cli.config import get_settings
|
|
40
47
|
from gflow_cli.data.recorder import OperationRecorder
|
|
41
48
|
from gflow_cli.errors import ConfigurationError, DataStoreError, WireFormatError
|
|
@@ -68,6 +75,10 @@ output_dir = "./out/my-movie" # optional
|
|
|
68
75
|
look = "cinematic, shallow depth of field"
|
|
69
76
|
palette = "warm golden tones"
|
|
70
77
|
negative = "no text, no watermark"
|
|
78
|
+
suffix = "Black and white cinematic street photography, photorealistic, film grain."
|
|
79
|
+
|
|
80
|
+
[style.variants.warm]
|
|
81
|
+
suffix = "Warm golden-hour cinematic grade."
|
|
71
82
|
|
|
72
83
|
[[characters]]
|
|
73
84
|
name = "Alice"
|
|
@@ -89,6 +100,7 @@ id = "arrival"
|
|
|
89
100
|
action = "walks through a busy futuristic plaza, looking around with wonder"
|
|
90
101
|
framing = "wide"
|
|
91
102
|
characters = ["Alice"]
|
|
103
|
+
style_variant = "warm" # select [style.variants.warm]; omit for base style
|
|
92
104
|
aspect = "16:9"
|
|
93
105
|
duration = 8
|
|
94
106
|
|
|
@@ -99,6 +111,7 @@ framing = "close-up"
|
|
|
99
111
|
characters = ["Alice"]
|
|
100
112
|
speaker = "Alice"
|
|
101
113
|
line = "We made it!"
|
|
114
|
+
style_suffix = "golden hour light" # appended after the variant/base suffix
|
|
102
115
|
aspect = "16:9"
|
|
103
116
|
duration = 6
|
|
104
117
|
model = "veo-quality"
|
|
@@ -257,15 +270,33 @@ def _print_header(manifest: MovieManifest, *, out_dir: Path, dry_run: bool) -> N
|
|
|
257
270
|
console.print(f" characters: {len(manifest.characters)} scenes: {len(manifest.scenes)}")
|
|
258
271
|
|
|
259
272
|
|
|
260
|
-
def
|
|
273
|
+
def _style_tag(s: Scene, style: StyleSpec) -> str:
|
|
274
|
+
"""Return the resolved-style fragment for the plan line, or ''."""
|
|
275
|
+
bits: list[str] = []
|
|
276
|
+
if s.style_variant:
|
|
277
|
+
bits.append(f"style={s.style_variant}")
|
|
278
|
+
elif style.suffix:
|
|
279
|
+
bits.append("style=base")
|
|
280
|
+
if s.style_suffix:
|
|
281
|
+
bits.append("+style_suffix")
|
|
282
|
+
return (" " + " ".join(bits)) if bits else ""
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def _format_scene_line(s: Scene, style: StyleSpec, *, done: bool, stale: bool, cost: int) -> str:
|
|
261
286
|
"""Return the single-line plan summary for one scene."""
|
|
262
287
|
mode = "r2v" if s.characters else "t2v"
|
|
263
288
|
refs = f" refs=[{', '.join(s.characters)}]" if s.characters else ""
|
|
264
289
|
framing_tag = f" {s.framing}" if s.framing else ""
|
|
265
290
|
model_tag = f" {s.model}" if s.model else ""
|
|
266
291
|
dur_tag = f" {s.duration}s" if s.duration else ""
|
|
267
|
-
|
|
268
|
-
|
|
292
|
+
if done:
|
|
293
|
+
status = "[dim]skip (done)[/dim]"
|
|
294
|
+
elif stale:
|
|
295
|
+
status = f"re-run (style changed) {cost} credit(s)"
|
|
296
|
+
else:
|
|
297
|
+
status = f"{cost} credit(s)"
|
|
298
|
+
style_tag = _style_tag(s, style)
|
|
299
|
+
return f" [{mode}] {s.id!r}{framing_tag}{model_tag}{dur_tag}{refs}{style_tag} {status}"
|
|
269
300
|
|
|
270
301
|
|
|
271
302
|
def _print_plan(manifest: MovieManifest, state: MovieState) -> None:
|
|
@@ -284,10 +315,14 @@ def _print_plan(manifest: MovieManifest, state: MovieState) -> None:
|
|
|
284
315
|
scene_credits = 0
|
|
285
316
|
for s in manifest.scenes:
|
|
286
317
|
done_state = state.scenes.get(s.id)
|
|
287
|
-
done =
|
|
318
|
+
done = False
|
|
319
|
+
stale = False
|
|
320
|
+
if done_state is not None and done_state.status == "completed":
|
|
321
|
+
stale = done_state.is_stale_for(compose_prompt(manifest.style, s, manifest.characters))
|
|
322
|
+
done = not stale
|
|
288
323
|
cost = 0 if done else 1
|
|
289
324
|
scene_credits += cost
|
|
290
|
-
console.print(_format_scene_line(s, done, cost))
|
|
325
|
+
console.print(_format_scene_line(s, manifest.style, done=done, stale=stale, cost=cost))
|
|
291
326
|
|
|
292
327
|
console.print(f"\n Estimated credits: ~{scene_credits}")
|
|
293
328
|
|
|
@@ -364,6 +399,7 @@ async def _run_one_scene(
|
|
|
364
399
|
status="completed",
|
|
365
400
|
prompt=prompt,
|
|
366
401
|
consistency_method="entity" if reference_entities else "text",
|
|
402
|
+
style_hash=resume_hash(prompt),
|
|
367
403
|
)
|
|
368
404
|
state.save(state_path)
|
|
369
405
|
console.print(f" saved: {video_result.local_path}")
|
|
@@ -390,6 +426,7 @@ async def _run_one_scene(
|
|
|
390
426
|
status="failed",
|
|
391
427
|
prompt=prompt,
|
|
392
428
|
consistency_method=failed_method,
|
|
429
|
+
style_hash=resume_hash(prompt),
|
|
393
430
|
)
|
|
394
431
|
state.save(state_path)
|
|
395
432
|
if continue_on_error:
|
|
@@ -468,11 +505,20 @@ async def _run_movie(
|
|
|
468
505
|
for scene in manifest.scenes:
|
|
469
506
|
scene_state = state.scenes.get(scene.id)
|
|
470
507
|
if scene_state is not None and scene_state.status == "completed":
|
|
471
|
-
|
|
472
|
-
if scene_state.
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
508
|
+
prompt_now = compose_prompt(manifest.style, scene, manifest.characters)
|
|
509
|
+
if scene_state.is_stale_for(prompt_now):
|
|
510
|
+
console.print(
|
|
511
|
+
f" Scene {scene.id!r} — prompt/style changed since last "
|
|
512
|
+
"run; regenerating."
|
|
513
|
+
)
|
|
514
|
+
else:
|
|
515
|
+
console.print(
|
|
516
|
+
f" [dim]Scene {scene.id!r} — already generated, skipping.[/dim]"
|
|
517
|
+
)
|
|
518
|
+
if scene_state.local_path:
|
|
519
|
+
completed_local_paths.append(Path(scene_state.local_path))
|
|
520
|
+
generated_any = True
|
|
521
|
+
continue
|
|
476
522
|
|
|
477
523
|
console.print(f"\n Generating scene [bold]{scene.id!r}[/bold]…")
|
|
478
524
|
local_path = await _run_one_scene(
|
|
@@ -8,6 +8,7 @@ the reusable seam a future second consumer (e.g. remotion) can import.
|
|
|
8
8
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
|
+
import hashlib
|
|
11
12
|
from collections.abc import Mapping
|
|
12
13
|
from dataclasses import dataclass, field
|
|
13
14
|
from pathlib import Path
|
|
@@ -16,7 +17,12 @@ from typing import Any, cast
|
|
|
16
17
|
|
|
17
18
|
@dataclass(frozen=True)
|
|
18
19
|
class StyleSpec:
|
|
19
|
-
"""Global guiding prompt — every field optional, reused verbatim per scene.
|
|
20
|
+
"""Global guiding prompt — every field optional, reused verbatim per scene.
|
|
21
|
+
|
|
22
|
+
``prefix`` / ``suffix`` are raw strings prepended / appended to the composed
|
|
23
|
+
prompt. ``variants`` is a name → suffix mapping that lets a manifest express
|
|
24
|
+
a style arc (e.g. monochrome → warm) without repeating text in every scene.
|
|
25
|
+
"""
|
|
20
26
|
|
|
21
27
|
look: str | None = None
|
|
22
28
|
palette: str | None = None
|
|
@@ -25,6 +31,22 @@ class StyleSpec:
|
|
|
25
31
|
lighting: str | None = None
|
|
26
32
|
mood: str | None = None
|
|
27
33
|
negative: str | None = None
|
|
34
|
+
prefix: str | None = None
|
|
35
|
+
suffix: str | None = None
|
|
36
|
+
variants: Mapping[str, str] = field(default_factory=dict[str, str])
|
|
37
|
+
|
|
38
|
+
def resolve_suffix(self, variant_name: str | None) -> str | None:
|
|
39
|
+
"""Return the named variant's suffix, or the base suffix when ``None``.
|
|
40
|
+
|
|
41
|
+
Raises ValueError on an unknown variant name (mirrors
|
|
42
|
+
``Character.resolve_variant``).
|
|
43
|
+
"""
|
|
44
|
+
if variant_name is None:
|
|
45
|
+
return self.suffix
|
|
46
|
+
if variant_name not in self.variants:
|
|
47
|
+
msg = f"unknown style variant {variant_name!r}"
|
|
48
|
+
raise ValueError(msg)
|
|
49
|
+
return self.variants[variant_name]
|
|
28
50
|
|
|
29
51
|
|
|
30
52
|
@dataclass(frozen=True)
|
|
@@ -100,6 +122,8 @@ class Scene:
|
|
|
100
122
|
model: str | None = None
|
|
101
123
|
aspect: str = "16:9"
|
|
102
124
|
count: int = 1
|
|
125
|
+
style_variant: str | None = None
|
|
126
|
+
style_suffix: str | None = None
|
|
103
127
|
|
|
104
128
|
|
|
105
129
|
def _sentence(text: str) -> str:
|
|
@@ -164,6 +188,20 @@ def _framing_camera_block(scene: Scene, style: StyleSpec) -> str:
|
|
|
164
188
|
return _sentence(framing_cam) if framing_cam else ""
|
|
165
189
|
|
|
166
190
|
|
|
191
|
+
def resolve_style_suffix(style: StyleSpec, scene: Scene) -> str | None:
|
|
192
|
+
"""Resolve the effective style suffix for a scene.
|
|
193
|
+
|
|
194
|
+
``scene.style_variant = "none"`` → opt out of base and variant suffixes
|
|
195
|
+
(``scene.style_suffix`` is independent and still applied); the manifest
|
|
196
|
+
parser rejects a variant literally named "none" so the sentinel cannot
|
|
197
|
+
shadow a real variant. Otherwise defer to :meth:`StyleSpec.resolve_suffix`
|
|
198
|
+
(variant suffix, or base ``style.suffix`` when no variant is set).
|
|
199
|
+
"""
|
|
200
|
+
if scene.style_variant == "none":
|
|
201
|
+
return None
|
|
202
|
+
return style.resolve_suffix(scene.style_variant)
|
|
203
|
+
|
|
204
|
+
|
|
167
205
|
def compose_prompt(
|
|
168
206
|
style: StyleSpec,
|
|
169
207
|
scene: Scene,
|
|
@@ -171,12 +209,17 @@ def compose_prompt(
|
|
|
171
209
|
) -> str:
|
|
172
210
|
"""Assemble the final Veo prompt deterministically (canonical order).
|
|
173
211
|
|
|
174
|
-
Order: action
|
|
175
|
-
framing+camera
|
|
176
|
-
global -> omit.
|
|
212
|
+
Order: [prefix] + action + subject(+variant) + setting + look + palette +
|
|
213
|
+
lighting + framing+camera + mood + dialogue + negative + [suffix].
|
|
214
|
+
Each slot: scene override -> global -> omit. ``negative`` MERGES
|
|
215
|
+
global+scene. ``prefix`` / ``suffix`` wrap the entire output.
|
|
177
216
|
"""
|
|
178
217
|
parts: list[str] = []
|
|
179
218
|
|
|
219
|
+
# 0. PREFIX (raw — wraps the entire prompt)
|
|
220
|
+
if style.prefix:
|
|
221
|
+
parts.append(style.prefix)
|
|
222
|
+
|
|
180
223
|
# 1. ACTION (required)
|
|
181
224
|
parts.append(_sentence(scene.action))
|
|
182
225
|
|
|
@@ -221,9 +264,28 @@ def compose_prompt(
|
|
|
221
264
|
if negs:
|
|
222
265
|
parts.append(f"Avoid: {', '.join(negs)}.")
|
|
223
266
|
|
|
267
|
+
# 11. SUFFIX (variant or base — raw)
|
|
268
|
+
suffix = resolve_style_suffix(style, scene)
|
|
269
|
+
if suffix:
|
|
270
|
+
parts.append(suffix)
|
|
271
|
+
|
|
272
|
+
# 12. SCENE STYLE_SUFFIX (raw, always last)
|
|
273
|
+
if scene.style_suffix:
|
|
274
|
+
parts.append(scene.style_suffix)
|
|
275
|
+
|
|
224
276
|
return " ".join(p for p in parts if p)
|
|
225
277
|
|
|
226
278
|
|
|
279
|
+
def resume_hash(prompt: str) -> str:
|
|
280
|
+
"""Return the full SHA-256 hex digest of *prompt* for resume change detection.
|
|
281
|
+
|
|
282
|
+
Same digest as ``gflow_cli.data.redaction.prompt_fields`` computes for
|
|
283
|
+
observability; duplicated here because this module deliberately imports
|
|
284
|
+
nothing from the rest of the package (pure seam).
|
|
285
|
+
"""
|
|
286
|
+
return hashlib.sha256(prompt.encode("utf-8")).hexdigest()
|
|
287
|
+
|
|
288
|
+
|
|
227
289
|
def _build_handoff_characters(manifest: Any, state: Any) -> list[dict[str, Any]]:
|
|
228
290
|
"""Build the ``characters`` list for the handoff manifest."""
|
|
229
291
|
chars_out: list[dict[str, Any]] = []
|
|
@@ -261,6 +323,19 @@ def _build_handoff_clip(
|
|
|
261
323
|
stored = getattr(ss, "prompt", None) if ss else None
|
|
262
324
|
prompt_val = stored or compose_prompt(manifest.style, scene, manifest.characters)
|
|
263
325
|
|
|
326
|
+
# Style applied — the styling baked into this clip's prompt. Resolved from
|
|
327
|
+
# the current manifest; the resume check in cli_movie regenerates a scene
|
|
328
|
+
# whenever its composed prompt changes, so this stays consistent with the
|
|
329
|
+
# stored prompt for every clip that survives a run.
|
|
330
|
+
style_applied: dict[str, Any] = {
|
|
331
|
+
"variant": scene.style_variant,
|
|
332
|
+
"prefix": manifest.style.prefix,
|
|
333
|
+
"suffix": resolve_style_suffix(manifest.style, scene),
|
|
334
|
+
"scene_suffix": scene.style_suffix,
|
|
335
|
+
}
|
|
336
|
+
if all(v is None for v in style_applied.values()):
|
|
337
|
+
style_applied = {}
|
|
338
|
+
|
|
264
339
|
return {
|
|
265
340
|
"id": scene.id,
|
|
266
341
|
"index": index,
|
|
@@ -274,6 +349,7 @@ def _build_handoff_clip(
|
|
|
274
349
|
],
|
|
275
350
|
"prompt": prompt_val,
|
|
276
351
|
"status": status,
|
|
352
|
+
"style_applied": style_applied,
|
|
277
353
|
"x_gflow": {
|
|
278
354
|
k: v
|
|
279
355
|
for k, v in (
|