gflow-cli 0.29.0__tar.gz → 0.30.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.29.0 → gflow_cli-0.30.0}/CHANGELOG.md +13 -1
- gflow_cli-0.30.0/GEMINI.md +37 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/PKG-INFO +1 -1
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/PLAN.md +3 -1
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/INDEX.md +1 -1
- gflow_cli-0.30.0/docs/LIVE_VERIFICATION_v0.30.0.md +53 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/MCP.md +1 -1
- gflow_cli-0.30.0/docs/superpowers/plans/2026-07-09-camoufox-adoption/PLAN.md +342 -0
- gflow_cli-0.30.0/docs/superpowers/spikes/2026-07-09-camoufox-waf-403.md +75 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/pyproject.toml +1 -1
- gflow_cli-0.30.0/scripts/spike_waf_camoufox.py +352 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/__init__.py +1 -1
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/transports/drivers/factory.py +6 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/cli_image.py +5 -2
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/recorder.py +9 -1
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/mcp/tools.py +35 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/data/test_recorder_character.py +48 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/mcp/test_tools_wired.py +74 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/uv.lock +1 -1
- gflow_cli-0.29.0/GEMINI.md +0 -34
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/README.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/commands/gflow/active.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/commands/gflow/branch-review.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/commands/gflow/changelog.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/commands/gflow/check.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/commands/gflow/doc-review.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/commands/gflow/issue-assessment.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/commands/gflow/issue-resolve.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/commands/gflow/known-issues.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/commands/gflow/next.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/commands/gflow/plan.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/commands/gflow/pr-council-review.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/commands/gflow/predict.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/commands/gflow/release.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/commands/gflow/scenario.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/commands/gflow/sonar.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.claude/commands/gflow/status.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.env.template +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.gitattributes +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.github/CODEOWNERS +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.github/copilot-instructions.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.github/dependabot.yml +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.github/workflows/ci.yml +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.github/workflows/external-pr-triage.yml +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.github/workflows/governance-advisory.yml +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.github/workflows/governance-benchmark.yml +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.github/workflows/main-base-guard.yml +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.github/workflows/release.yml +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.gitignore +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.gitleaks.toml +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.pre-commit-config.yaml +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/.secrets.baseline +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/AGENTS.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/CLAUDE.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/CONFIGURATION.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/CONTRIBUTING.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/DISCLAIMER.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/KNOWN_ISSUES.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/LICENSE +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/README.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/RELEASE.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/ROADMAP.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/conftest.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docker-compose.yml +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/AGENT_GUIDE.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/AGENT_UI_E2E.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/AGENT_UI_RECON.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/ARCHITECTURE.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/AUTHENTICATION.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/CHARACTER.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/CHARACTER_RECON.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/CONFIGURATION.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/DATA_LAYER.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/DEBUGGING.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/DEMOS.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/DEVELOPMENT.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/E2E_TESTING.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/EXTERNAL_STORAGE.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/GITHUB.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/GOVERNANCE_BENCHMARK.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/IMAGE_UPSCALE_RECON.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/INSTRUCTIONS.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_data_layer.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_image_batch.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.10.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.11.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.12.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.13.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.16.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.17.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.18.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.19.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.20.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.20.1.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.21.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.22.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.23.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.24.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.25.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.26.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.27.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.27.1.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.28.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.29.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.7.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.8.1.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.9.0.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_v0.9.1.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/LIVE_VERIFICATION_video_download.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/MOVIE.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/PROJECT_STATUS.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/PROMPT_EXPANSION.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/SECURITY.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/TOOLS.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/USAGE.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/USER_GUIDE.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/assets/demo-split-pf.gif +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/assets/example-run.gif +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/assets/examples.webp +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/medium_tutorial.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/schemas/movie-handoff.schema.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/sonar-cleanup-tracker.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/superpowers/plans/2026-06-12-issue-174-library-ui-attach/PLAN.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/superpowers/plans/2026-06-22-mcp-server/PLAN.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/superpowers/plans/2026-06-22-mcp-server/PREDICT.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/superpowers/plans/2026-06-22-mcp-server/SCENARIO.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/superpowers/plans/2026-06-22-prompt-expansion/PLAN.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/superpowers/plans/2026-06-22-prompt-expansion/PREDICT.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/superpowers/plans/2026-06-22-prompt-expansion/SCENARIO.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/superpowers/plans/2026-06-24-gflow-studio-scaffold/PLAN.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/superpowers/plans/2026-06-24-rest-api-layer/PLAN.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/superpowers/plans/2026-06-26-mcp-e2e-test/PLAN.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/superpowers/research/2026-06-27-tool-abstraction-evaluation.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/docs/superpowers/specs/2026-06-29-issue-assessment-workflow-design.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/examples/README.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/examples/batch_from_config.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/examples/multi_prompt_t2i.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/examples/sample_config.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/examples/sample_prompts.txt +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/examples/single_image_t2i.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/examples/workflow_chain.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/llms.txt +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/samples/README.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/samples/captured/01_upload_image.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/samples/captured/02_batchAsyncGenerateVideoText.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/samples/captured/04_archive_workflow.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/samples/captured/05_createProject.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/samples/captured/06_batchGenerateImages.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/samples/captured/07_batchGenerateImages_seeded.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/samples/captured/08_batchAsyncGenerateVideoStartAndEndImage.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/samples/captured/09_batchAsyncGenerateVideoReferenceImages.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/samples/captured/10_batchCheckAsyncVideoGenerationStatus_successful.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/samples/captured/11_batchCheckAsyncVideoGenerationStatus_failed.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/samples/captured/12_create_scene.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/samples/captured/13_sceneWorkflows_update.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/samples/captured/14_get_scene_workflows.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/samples/captured/15_commit_flowWorkflow.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/ci/check_doc_links.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/ci/check_materiality.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/ci/check_repo_hygiene.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/debug_editor.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/debug_gen_settings.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/debug_settings.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/_recording_client.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/_spike_common.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/active_plan.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/analyze_agent_ui_capture.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/capture_i2v_frame_slots_dom.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/capture_i2v_intercept_submit.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/capture_i2v_model_select_repro.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/capture_i2v_post_bind_state.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/capture_image_add_media_dom.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/capture_locale_invariants.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/cdp_drive_and_probe.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/character_create_spike.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/character_create_spike_v2.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/dump_character_selectors.js +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/make_project.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/materiality_backtest.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/monitor_pr_38.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/patch_character.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/skillopt/README.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/skillopt/harness.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/skillopt/tasks.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/spike_char_editor_dom.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/spike_char_gen_capture.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/spike_image_upscale_capture.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/spike_image_upscale_drive.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/spike_image_upscale_recaptcha_action.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/spike_image_upscale_rest_probe.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/spike_issue170_picker_locale_recon.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/spike_issue174_library_ui_recon.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/spike_movie_attach_payload.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/spike_movie_entity_recon.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/spike_movie_gen_capture.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/spike_movie_picker_select.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/spike_movie_voice_list.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/spike_patch_entity.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/dev/spike_patchright.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/diag/README.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/diag/capture_flow_traffic.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/diag/memory_profile.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/diag/recaptcha_mint.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/e2e/agentic_image_e2e.ps1 +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/e2e/capture_agent_toggle.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/record_demo.ps1 +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/smoke_image.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/smoke_real_chrome_image.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/smoke_video_editor.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/smoke_worker_style.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/scripts/verify_chrome_auth_viability.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/skills/README.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/skills/gflow-cli/SKILL.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/skills/issue-assessment/SKILL.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/skills/issue-resolve/SKILL.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/skills/plan/SKILL.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/skills/pr-council-review/SKILL.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/skills/predict/SKILL.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/skills/scenario/SKILL.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/skills/status/SKILL.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/sonar-project.properties +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/__main__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/_cli_helpers.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/_engine.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/_retry.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/_sapisidhash.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/character.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/client.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/dto.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/image.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/image_upscale.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/recaptcha.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/routes.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/scene.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/transports/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/transports/_common.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/transports/_fingerprint.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/transports/base.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/transports/drivers/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/transports/drivers/agentic.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/transports/drivers/base.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/transports/drivers/classic.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/transports/experimental/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/transports/experimental/bearer.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/transports/experimental/evaluate_fetch.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/transports/experimental/sapisidhash.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/transports/ui_automation.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/transports/ui_automation_video.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/api/video.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/auth/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/auth/base.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/auth/cookies.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/auth/factory.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/auth/internal_chromium.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/auth/real_chrome.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/auth/strategies.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/auth/verification.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/browser_manager.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/chain.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/chain_manifest.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/cli.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/cli_character.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/cli_data.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/cli_instructions.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/cli_models.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/cli_movie.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/cli_run.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/cli_scene.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/cli_tools.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/cli_video.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/composition.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/config.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/chain_repo.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/migrations/0001_initial.sql +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/migrations/0002_add_cloud_storage.sql +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/migrations/0003_add_scene_tables.sql +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/migrations/0004_add_scene_output_path.sql +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/migrations/0005_add_chain_links.sql +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/migrations/0006_add_operations_metadata.sql +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/migrations/0007_queue.sql +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/migrations/0008_add_operation_expanded_prompt.sql +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/migrations/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/models.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/queries.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/redaction.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/repository.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/data/store.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/errors.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/exceptions.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/image_batch.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/json_output.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/manifest.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/mcp/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/mcp/prompts.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/mcp/resources.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/mcp/server.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/media.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/movie_manifest.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/observability.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/paths.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/profile_store.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/services/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/services/character_create.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/storage.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/tools/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/tools/banned.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/tools/builtin/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/tools/builtin/creative-director.toml +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/tools/expander.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/tools/invocation.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/tools/loader.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/tools/registry.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/tools/runtime.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/tools/spec.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/ui/app.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/ui/server.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/worker/daemon.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/src/gflow_cli/worker/queue.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tasks/lessons.md +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/test_assets/sample_batch.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/test_assets/sample_batch.tsv +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/test_assets/sample_batch_invalid.tsv +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/fixtures/character_gen_response.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/fixtures/patch_entity_response.json +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_aisandbox_auth_error.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_aisandbox_auth_headers.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_bearer_redaction.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_character.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_client.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_client_character.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_client_delete_characters.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_client_generate_character.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_client_image.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_client_launch_kwargs.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_client_patch_entity.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_client_scene.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_client_upscale.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_concurrency.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_dto.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_engine.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_image.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_image_dto.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_image_upscale.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_post_json_aisandbox_auth.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_recaptcha.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_retry.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_routes.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_routes_character.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_routes_scene.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_sapisidhash_helper.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_scene_models.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_video.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/test_video_request.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/conftest.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/drivers/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/drivers/test_agentic.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/drivers/test_factory.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/test_base.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/test_bearer.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/test_common.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/test_evaluate_fetch.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/test_factory.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/test_fingerprint.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/test_sapisidhash.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/test_selector_symmetry.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/test_transport_timeout.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/test_ui_automation.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/test_ui_automation_batch.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/test_ui_automation_image_mode.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/test_ui_automation_video.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/api/transports/test_ui_character_editor.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/auth/strategies/test_factory.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/auth/strategies/test_strategies.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/auth/test_cookies.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/auth/test_verification.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_cli_auth_list.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_cli_character.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_cli_character_create.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_cli_data.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_cli_image.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_cli_image_seed_removed.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_cli_image_selector_drift.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_cli_image_upscale.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_cli_instructions.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_cli_models.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_cli_movie.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_cli_run.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_cli_scene.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_cli_tools.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_cli_video.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_cli_video_chain.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_error_handling.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_helpers.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_movie_manifest.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_movie_manifest_style_variants.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_settings_validation.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/cli/test_t2i_multi_prompt.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/composition/test_character.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/composition/test_compose_prompt.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/composition/test_handoff.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/composition/test_style_variants.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/composition/test_style_variants_e2e.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/conftest.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/data/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/data/test_chain_repo.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/data/test_find_incomplete_character.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/data/test_models.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/data/test_packaging.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/data/test_recorder.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/data/test_redaction.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/data/test_repository.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/data/test_scene_persistence.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/data/test_settings_and_errors.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/data/test_store_migrations.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/dev/test_recording_client.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/conftest.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_aisandbox_auth_live.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_auth_verification_e2e.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_chain_e2e.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_character_create_e2e.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_daemon_e2e.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_data_layer_e2e.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_i2v_flags_e2e.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_image_batch_e2e.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_image_i2i_ref_cap_e2e.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_json_output_e2e.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_live_agentic_instructions.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_locale_selectors_e2e.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_scene_compose_live.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_tools_e2e.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_transports_e2e.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_video_r2v_ref_cap_e2e.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/e2e/test_video_t2v_e2e.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/auth.feature +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/auth_login.feature +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/character_create.feature +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/character_read.feature +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/conftest.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/image.feature +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/image_upscale.feature +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/instructions.feature +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/locale_picker_include.feature +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/test_auth_login_steps.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/test_auth_steps.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/test_character_create_steps.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/test_character_read_steps.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/test_image_steps.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/test_image_upscale_steps.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/test_instructions_steps.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/test_locale_picker_include_steps.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/test_step_collision_guard.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/test_video_agent_ui_steps.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/test_video_chain_steps.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/video_agent_ui.feature +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/features/video_chain.feature +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/fixtures/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/fixtures/seeded_catalog.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/image_batch/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/image_batch/test_image_manifest.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/image_batch/test_observability_events.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/integration/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/integration/conftest.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/integration/constants.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/integration/test_storage_gcs.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/integration/test_storage_s3.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/mcp/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/mcp/conftest.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/mcp/test_cli_parity.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/mcp/test_server.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/mcp/test_stdio_transport.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/mcp/test_tools_helpers.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/mcp/test_tools_instructions.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/scripts/test_analyze_agent_ui_capture.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/scripts/test_capture_locale_invariants.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/scripts/test_check_materiality.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/scripts/test_check_repo_hygiene.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/scripts/test_materiality_backtest.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/services/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/services/test_character_create_redaction.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/services/test_character_create_saga.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/services/test_character_gen_no_direct_post.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/smoke/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/smoke/test_profile_account_smoke.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/smoke/test_real_flow.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_auth.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_browser_manager.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_chain.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_chain_manifest.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_cli_data.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_config.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_conftest_isolation.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_data_queries.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_documentation_gate.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_errors.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_errors_403.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_json_output.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_manifest.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_marker_registry.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_media.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_observability.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_paths.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_profile_store.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/test_smoke.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/tools/__init__.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/tools/test_banned.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/tools/test_expander.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/tools/test_invocation.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/tools/test_loader.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/tools/test_registry.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/tools/test_runtime.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/tools/test_spec.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/ui/test_app.py +0 -0
- {gflow_cli-0.29.0 → gflow_cli-0.30.0}/tests/worker/test_daemon.py +0 -0
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.30.0] — 2026-07-09
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **MCP `gflow_generate_video` model/duration/count parameters (CLI↔MCP parity):** agents can now select the Veo model (`veo_lite`/`veo_fast`/`veo_quality`/`omni_flash`, aliases accepted), clip duration, and batch count through MCP, matching the CLI `gflow video` flags. An unknown model is rejected up front with a 400 instead of failing deep in the worker; an omitted model still lets the transport apply its i2v veo-lite default (issue #125). Co-authored-by C1ph3r404 (from the closed PR #258). Note: the pre-existing transport-level i2v veo-lite default already protected the MCP path, so this is parity + agent control, not a new credit guard.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- **Character-create recorder no longer crashes on a duplicated `flow_media_id`.** Under the agentic cohort the classic character-editor slot-add control is absent, so the body prompt lands in the still-active face slot and both slots report the same `flow_media_id`; `_record_character_local_files` minted a fresh asset `id` per slot and the second slot violated `UNIQUE(profile_name, flow_media_id)` → `DataIntegrityError`. The recorder now reuses the existing asset id (mirroring `record_completed_video`), making character local-file recording idempotent on the business key. Regression test in `tests/data/test_recorder_character.py`.
|
|
19
|
+
- **`prefer_classic` no longer logs a misleading `WARNING` on the agentic cohort.** The server-gated agentic (`tune`) cohort cannot be exited client-side, and `prefer_classic` is best-effort by contract, so `get_ui_driver` now logs that expected fall-through at `INFO` (`ui_driver.prefer_classic.cohort_natively_agentic`) and reserves `WARNING` for genuinely unexpected exit failures.
|
|
20
|
+
|
|
10
21
|
## [0.29.0] — 2026-07-09
|
|
11
22
|
|
|
12
23
|
### Added
|
|
@@ -1887,7 +1898,8 @@ shell-script template that branches on these codes.
|
|
|
1887
1898
|
|
|
1888
1899
|
First skeleton. Not functional end-to-end yet.
|
|
1889
1900
|
|
|
1890
|
-
[Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.
|
|
1901
|
+
[Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.30.0...HEAD
|
|
1902
|
+
[0.30.0]: https://github.com/ffroliva/gflow-cli/compare/v0.29.0...v0.30.0
|
|
1891
1903
|
[0.29.0]: https://github.com/ffroliva/gflow-cli/compare/v0.28.0...v0.29.0
|
|
1892
1904
|
[0.28.0]: https://github.com/ffroliva/gflow-cli/compare/v0.27.1...v0.28.0
|
|
1893
1905
|
[0.27.1]: https://github.com/ffroliva/gflow-cli/compare/v0.27.0...v0.27.1
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# GEMINI.md
|
|
2
|
+
|
|
3
|
+
> Project memory hub for **Gemini CLI**. The universal coding-agent rules for any tool (Cursor, Codex, Aider, Gemini CLI, etc.) live in [AGENTS.md](AGENTS.md) — this file carries Gemini-specific session protocol only.
|
|
4
|
+
|
|
5
|
+
## What this project is
|
|
6
|
+
|
|
7
|
+
`gflow-cli` is an unofficial Python CLI that drives [Google Flow](https://labs.google/fx/tools/flow) (Veo image-to-video, Imagen text-to-image) from the terminal by reverse-engineering Flow's private REST API. See [README.md](README.md) for the user-facing overview.
|
|
8
|
+
|
|
9
|
+
## On every session start
|
|
10
|
+
|
|
11
|
+
1. Read **[AGENTS.md](AGENTS.md)** — universal rules every agent must follow.
|
|
12
|
+
2. Read **[docs/INDEX.md](docs/INDEX.md)** — routing layer for all project docs and commands.
|
|
13
|
+
3. Pull deeper context on demand (type as plain text in the `agy` TUI prompt):
|
|
14
|
+
- Current task / where we left off → `gflow:status`
|
|
15
|
+
- Starting a new feature → `gflow:predict` → `gflow:scenario` → `gflow:plan <feature>`
|
|
16
|
+
- Touching auth or reCAPTCHA → `gflow:known-issues`
|
|
17
|
+
- Cutting a release → `gflow:release`
|
|
18
|
+
- Before any commit → `gflow:check`
|
|
19
|
+
|
|
20
|
+
## Gemini-specific
|
|
21
|
+
|
|
22
|
+
- Use specialized skills when relevant (e.g., `find-docs` for library research, `pr-council-review` for PR audits).
|
|
23
|
+
- Maintain memory via the `mcp-mempalace` tool if available.
|
|
24
|
+
- Prioritize **turn efficiency** and **high-signal output**.
|
|
25
|
+
|
|
26
|
+
## Active phase
|
|
27
|
+
|
|
28
|
+
- **v0.29.0 shipped (2026-07-09):** persistent `gflow instructions` CRUD + movie-manifest instructions brief-sync + six `gflow_instructions_*` MCP tools, with a CI-enforced MCP↔CLI parity contract (`tests/mcp/test_cli_parity.py`) and the agentic-indicator selectors consolidated onto `drivers/factory.py`. Released to PyPI; issue #192 closed.
|
|
29
|
+
- **PR #258 (Camoufox stealth engine, external contribution) — taken over and CLOSED-OUT (2026-07-09).** A 5-persona `/gflow:predict` rejected a rebase in favour of a decomposed, evidence-gated series: Phase 1 landed the MCP video param parity (#273, contributor-credited); a WAF-evidence harness (#274/#275) measured a **0.0% WAF 403 rate over 20 live generations**, so per ADR-13 the Camoufox engine was **NOT built** (#276). The i2i "UUID-ref bug" was investigated and found not-a-bug (#277, stale comment fixed). Contributor thanked + credited on the closed PR. Evidence: `docs/superpowers/spikes/2026-07-09-camoufox-waf-403.md`.
|
|
30
|
+
- **Decoupled Daemon/Worker Plan:** The MCP→FlowWorker wiring shipped in v0.23.0 (PR #228). The remaining headless SSE Daemon + Tauri/React editor blueprint is scheduled in [gflow-studio-scaffold/PLAN.md](file:///C:/development/github/gflow-cli/docs/superpowers/plans/2026-06-24-gflow-studio-scaffold/PLAN.md) and [rest-api-layer/PLAN.md](file:///C:/development/github/gflow-cli/docs/superpowers/plans/2026-06-24-rest-api-layer/PLAN.md).
|
|
31
|
+
- **Core Lesson (Retrospective):**
|
|
32
|
+
- **Verify before adopting — measure, don't assume.** The PR #258 takeover's value was checking every claim against the real code and real data instead of adopting on assertion: a stealth engine we didn't build (0% WAF baseline), a "credit guard" already enforced one layer down, a `display_name` already shipped in v0.26.0, an i2i "bug" that wasn't one, and a concurrency bug that never merged. Five claims, five dismissals — the cheapest correct outcome came from investigation, not implementation.
|
|
33
|
+
- **ADR gates pay for themselves.** ADR-13 ("confirm the current stealth fix insufficient before implementing an alternative") turned a "build Camoufox" epic into a one-afternoon 20-generation spike that said "don't." Encode the gate as a runnable measurement (`scripts/spike_waf_camoufox.py`), not a debate.
|
|
34
|
+
- **Decompose contested external PRs; never rebase a branch that's 60+ commits behind.** Cherry-pick/re-express the genuinely-valuable pieces onto fresh branches with `Co-authored-by` credit, evidence-gate the risky parts, and split by concern — one PR per slice.
|
|
35
|
+
- Kept `gflow-cli` strictly headless (Uvicorn + FastMCP over localhost HTTP/SSE); browser-context locks bypassed by serializing task writes in the SQLite queue with WAL-mode parallel reads. Relational instruction cards must be phrased conversationally (imperative prompts bypass the brief); multi-scene movie sync is read-modify-write to preserve server-assigned card IDs.
|
|
36
|
+
|
|
37
|
+
See [PLAN.md](PLAN.md) or type `gflow:status` for the current task. Type `gflow:plan <feature>` to create a new feature plan.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gflow-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.30.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
|
|
@@ -653,6 +653,8 @@ Records image, batch, T2V, I2V, and R2V provenance in a local SQLite catalog. Re
|
|
|
653
653
|
|
|
654
654
|
**Status:** NOT implemented. Parked until the stealth-flag fix (`--disable-blink-features=AutomationControlled` + init script) is confirmed insufficient, or until a contributor picks it up.
|
|
655
655
|
|
|
656
|
+
**2026-07-09 verification — the current stealth fix is CONFIRMED SUFFICIENT (so this stays parked).** A 20-generation baseline on a live authed profile through the default stealth stack produced a **0.0% WAF 403 rate** (19/20 success; the one miss was a UI-scrape timeout, not a WAF block). This met ADR-13's "must verify before implementing" gate and closed the [Camoufox adoption roadmap](superpowers/plans/2026-07-09-camoufox-adoption/PLAN.md) at Phase 2 — the Camoufox engine was NOT built. Evidence: [superpowers/spikes/2026-07-09-camoufox-waf-403.md](superpowers/spikes/2026-07-09-camoufox-waf-403.md). Re-run `scripts/spike_waf_camoufox.py` if a repeatable WAF-403 is later observed; a materially non-zero rate would reopen CDP-Attach / Camoufox.
|
|
657
|
+
|
|
656
658
|
---
|
|
657
659
|
|
|
658
660
|
### Phase 8 — Pluggable storage backend — BACKLOG
|
|
@@ -699,7 +701,7 @@ Today the CLI writes media to `$GFLOW_CLI_OUTPUT_DIR` on the local filesystem. P
|
|
|
699
701
|
| 10 | Both `gflow` and `flow` binary names installed | `flow` is friendlier; `gflow` avoids conflicts with Facebook Flow / MS Power Automate |
|
|
700
702
|
| 11 | LF-only line endings via `.gitattributes` | Single repo source of truth; cross-platform contributors don't think about it |
|
|
701
703
|
| 12 | `Provider` indirection (legacy `providers/`) removed | Superseded by `api.FlowApiClient`. Re-introduce when we add `OfficialVeoProvider` (planned v0.5+) |
|
|
702
|
-
| 13 | CDP attach
|
|
704
|
+
| 13 | CDP attach / stealth-engine alternatives deferred; **current stealth fix confirmed sufficient 2026-07-09** | Gate met: a 20-gen live baseline through the default stealth stack showed a **0.0% WAF 403 rate**, so the "confirm insufficient before implementing" bar is unmet — CDP-Attach and the Camoufox engine stay parked (Camoufox roadmap closed at Phase 2). Evidence: [superpowers/spikes/2026-07-09-camoufox-waf-403.md](superpowers/spikes/2026-07-09-camoufox-waf-403.md). |
|
|
703
705
|
| 14 | HTTP status path (`get_video_status`) retired alongside `generate_video` | It is the same 401-dead path and would collide with the new `api/video.py:VideoStatus` value object — retiring both together keeps the domain clean. |
|
|
704
706
|
|
|
705
707
|
---
|
|
@@ -122,7 +122,7 @@ Slash commands for Claude Code, stored in `.claude/commands/gflow/`. All prefixe
|
|
|
122
122
|
**"A gflow command hangs / fails — where do I start?"** → [DEBUGGING § Quick reference](DEBUGGING.md#quick-reference)
|
|
123
123
|
**"Flow's UI broke a selector — how do I diagnose it?"** → [DEBUGGING § Inspecting Flow's live UI](DEBUGGING.md#inspecting-flows-live-ui)
|
|
124
124
|
**"What does each `ui_automation.*` log event mean?"** → [DEBUGGING § Listener & HTTP-layer debugging](DEBUGGING.md#listener--http-layer-debugging)
|
|
125
|
-
**"What was actually live-verified for the latest release?"** → latest: [LIVE_VERIFICATION_v0.29.0](LIVE_VERIFICATION_v0.29.0.md) (**persistent `gflow instructions` CRUD proven live e2e GREEN, credit-free** — 11-command sequence on a fresh project: add incl. `--ref <image-UUID>` attach, list/enable/disable, master toggle both ways, TOML `apply` destructive full-sync with `enabled=false` honored, `rm` with server card-id preserved across mutations; movie brief-sync code-path-verified via the same primitives, deferred-with-reason on credits; MCP `gflow_instructions_*` tools are thin adapters over the live-verified primitives). Prior: [v0.28.0](LIVE_VERIFICATION_v0.28.0.md) (**agent instructions `-i` now steer agentic generation — crayon e2e GREEN**: a style-neutral prompt + an enabled "crayon" card produced an unmistakable crayon drawing through the real transport; root causes were conversational phrasing + the `project_brief.enabled` master switch). Prior: [v0.27.1](LIVE_VERIFICATION_v0.27.1.md) (**v0.27.0 release follow-up fixes and documentation sync**). Prior: [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)
|
|
125
|
+
**"What was actually live-verified for the latest release?"** → latest: [LIVE_VERIFICATION_v0.30.0](LIVE_VERIFICATION_v0.30.0.md) (**agentic-cohort image path + both fixes live-verified credit-free** — native 768×1376 stills, i2i-chain + canonical-ref identity hold; the character-create `DataIntegrityError` and the `prefer_classic` WARNING were observed live then fixed [recorder idempotent + INFO log]; MCP video-param feature deferred-with-reason on Veo credits, per the stills-only goal). Prior: [v0.29.0](LIVE_VERIFICATION_v0.29.0.md) (**persistent `gflow instructions` CRUD proven live e2e GREEN, credit-free** — 11-command sequence on a fresh project: add incl. `--ref <image-UUID>` attach, list/enable/disable, master toggle both ways, TOML `apply` destructive full-sync with `enabled=false` honored, `rm` with server card-id preserved across mutations; movie brief-sync code-path-verified via the same primitives, deferred-with-reason on credits; MCP `gflow_instructions_*` tools are thin adapters over the live-verified primitives). Prior: [v0.28.0](LIVE_VERIFICATION_v0.28.0.md) (**agent instructions `-i` now steer agentic generation — crayon e2e GREEN**: a style-neutral prompt + an enabled "crayon" card produced an unmistakable crayon drawing through the real transport; root causes were conversational phrasing + the `project_brief.enabled` master switch). Prior: [v0.27.1](LIVE_VERIFICATION_v0.27.1.md) (**v0.27.0 release follow-up fixes and documentation sync**). Prior: [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)
|
|
126
126
|
**"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.
|
|
127
127
|
**"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)
|
|
128
128
|
**"What was live-verified for the video-download feature (#29)?"** → [LIVE_VERIFICATION_video_download](LIVE_VERIFICATION_video_download.md)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Live Verification — v0.30.0
|
|
2
|
+
|
|
3
|
+
Release gate evidence for the user-facing changes in v0.30.0, using the 5-layer
|
|
4
|
+
ledger (file count · magic bytes · dimensions/shape · structlog invariants ·
|
|
5
|
+
user-confirmable artifact). Credit-free wherever possible.
|
|
6
|
+
|
|
7
|
+
## Scope of v0.30.0
|
|
8
|
+
|
|
9
|
+
- **Added:** MCP `gflow_generate_video` model/duration/count parameters (CLI↔MCP parity, #125).
|
|
10
|
+
- **Fixed:** agentic character-recorder idempotency (DataIntegrityError); `prefer_classic`
|
|
11
|
+
WARNING→INFO on the server-gated agentic cohort.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 1. Agentic-cohort image path + both Fixed items — LIVE, credit-free ✅
|
|
16
|
+
|
|
17
|
+
Exercised end-to-end on **2026-07-09** against live Flow (account `denon82`, **agentic**
|
|
18
|
+
cohort) as part of the parable image-consistency spike. Image generation is **credit-free**
|
|
19
|
+
(no Veo credits).
|
|
20
|
+
|
|
21
|
+
- **File count:** multiple stills downloaded per run (t2i baseline, i2i chain, canonical-ref,
|
|
22
|
+
multi-ref) — 1 file per generation, all present on disk.
|
|
23
|
+
- **Magic bytes:** JPEG (`ffprobe`-decodable) for every downloaded still.
|
|
24
|
+
- **Dimensions/shape:** **768×1376** (native 9:16) on every generation — the no-crop invariant
|
|
25
|
+
held under the agentic cohort.
|
|
26
|
+
- **Structlog invariants:** the two Fixed conditions were **observed live** before the fix and
|
|
27
|
+
are now handled:
|
|
28
|
+
- `ui_driver.prefer_classic.exit_agent_failed` (WARNING) fired on the agentic (`tune`) cohort —
|
|
29
|
+
now logged at INFO (`ui_driver.prefer_classic.cohort_natively_agentic`); best-effort by contract.
|
|
30
|
+
- `character create` on the agentic cohort raised `DataIntegrityError`
|
|
31
|
+
(`UNIQUE constraint failed: assets.profile_name, assets.flow_media_id`) — now idempotent
|
|
32
|
+
(recorder reuses the existing asset id). Covered by regression test
|
|
33
|
+
`tests/data/test_recorder_character.py::test_record_character_completed_duplicate_media_id_is_idempotent`.
|
|
34
|
+
- **User-confirmable artifact:** the side-by-side still gallery + scorecard recorded in the
|
|
35
|
+
consuming project's spike results (`out/spike/…` + `docs/superpowers/specs/2026-07-09-parable-image-consistency-spike-results.md`).
|
|
36
|
+
|
|
37
|
+
## 2. MCP `gflow_generate_video` params (#125) — deferred this cycle, unit-test-covered ⚠️
|
|
38
|
+
|
|
39
|
+
This feature is exercised only by **video generation**, which **costs Veo credits**, and the
|
|
40
|
+
consuming pipeline's explicit goal this cycle is **stills-only (skip video generation)**. Per the
|
|
41
|
+
release gate's escape hatch, it is **not live-verified this cycle** for that reason — it is **not
|
|
42
|
+
silently omitted**. Coverage:
|
|
43
|
+
|
|
44
|
+
- Unit/contract tests: `tests/mcp/` (including the MCP↔CLI parity contract
|
|
45
|
+
`tests/mcp/test_cli_parity.py`) — model/duration/count validation and the 400-on-unknown-model
|
|
46
|
+
path are covered without spending credits.
|
|
47
|
+
- Recommended follow-up: a credit-spending i2v smoke on the next cycle that budgets Veo credits.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
**Gate summary:** ruff ✓ · format ✓ · pyright 0 errors ✓ · pytest 2145 passed / 7 skipped ✓ ·
|
|
52
|
+
repo-hygiene exit 0 ✓. Agentic image path + both fixes live-verified credit-free; MCP video
|
|
53
|
+
feature deferred with documented reason.
|
|
@@ -46,7 +46,7 @@ The server registers three protocol surfaces:
|
|
|
46
46
|
|
|
47
47
|
### Tools (Executable actions)
|
|
48
48
|
* `gflow_generate_image(prompt, model, aspect, count, seed, reference_images, tools, profile, project, instructions)`: Triggers text-to-image / image-to-image (Imagen / Nano Banana). `instructions` is an optional list of ephemeral agent-instruction strings (agentic cohort only). `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).
|
|
49
|
+
* `gflow_generate_video(prompt, mode, aspect, initial_frame, end_frame, reference_images, model, duration, count, tools, profile, project)`: Triggers vertical or landscape video generation (Veo). `mode` is `t2v`/`i2v`/`r2v`; `model` (`veo_lite`/`veo_fast`/`veo_quality`/`omni_flash`, aliases accepted), `duration` (seconds), and `count` mirror the CLI `gflow video` flags — an omitted `model` lets the transport apply its i2v veo-lite default (issue #125), and `omni_flash` is rejected for i2v-with-frames; `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
|
* `gflow_list_tools()`: Lists the prompt tools (name/title/description/category) accepted by the generate tools' `tools` param.
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# Camoufox Adoption Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** Run `/gflow:status --feature camoufox-adoption` to find the
|
|
4
|
+
> next unchecked task. Implement one task at a time. Run `/gflow:check` before every commit.
|
|
5
|
+
> This plan supersedes PR #258 (closed) — it re-expresses that contributor work as a
|
|
6
|
+
> gated, decomposed series. Preserve `Co-authored-by: C1ph3r404 <C1ph3r404@users.noreply.github.com>`
|
|
7
|
+
> on every commit that carries their code.
|
|
8
|
+
>
|
|
9
|
+
> **STATUS (2026-07-09): Phase 1 shipped (PR #273); Phase 2 verdict = STOP — the Camoufox
|
|
10
|
+
> engine (Phase 3) is NOT built because the current stealth fix showed a 0.0% WAF 403 rate.
|
|
11
|
+
> See Phase 2 below + `docs/superpowers/spikes/2026-07-09-camoufox-waf-403.md`. Phase 4 items
|
|
12
|
+
> remain independent backlog.**
|
|
13
|
+
|
|
14
|
+
**Goal:** Adopt Camoufox as an optional, evidence-justified stealth browser engine for
|
|
15
|
+
WAF-blocked users — without regressing the default (playwright) path — landing the
|
|
16
|
+
engine-independent fixes from PR #258 immediately and the engine itself only after it is
|
|
17
|
+
proven to beat the incumbent stealth story.
|
|
18
|
+
|
|
19
|
+
**Architecture:** Camoufox slots into the existing engine abstraction (`api/_engine.py` +
|
|
20
|
+
`config.BrowserEngine`, the patchright precedent from v0.19.0). The current port
|
|
21
|
+
(`resolve_async_playwright`) is too narrow for Camoufox (its own async CM yielding a Firefox
|
|
22
|
+
`BrowserContext`, no Playwright driver), so Phase 3 **widens `_engine.py` into a single
|
|
23
|
+
context-launching adapter + an `EngineQuirks` capabilities value**. All engine conditionals
|
|
24
|
+
resolve once at setup and thread down as quirks — never inline `settings.browser_engine ==`
|
|
25
|
+
checks in transports/drivers. The default and patchright paths stay byte-for-byte unchanged.
|
|
26
|
+
|
|
27
|
+
**Predict verdict:** CAUTION — confidence 7/10 (Architect 8 · Security 8 · Performance 7 ·
|
|
28
|
+
CLI-UX 8 · Devil's-Advocate 8). Five-persona review 2026-07-09. Full takeover-by-rebase
|
|
29
|
+
was rejected unanimously in favour of cherry-pick/re-express, split by concern, gated by a
|
|
30
|
+
WAF-evidence spike per ADR-13.
|
|
31
|
+
|
|
32
|
+
**ADR gate (blocking for Phase 3):** PLAN.md Decision Log #13 + the CDP-Attach backlog park
|
|
33
|
+
all stealth-engine alternatives "until the stealth-flag fix is **confirmed insufficient** —
|
|
34
|
+
this must be verified before implementing anything." Phase 2 produces that verification.
|
|
35
|
+
Camoufox engine code (Phase 3) MUST NOT merge until Phase 2 shows a real 403-rate win.
|
|
36
|
+
|
|
37
|
+
**Risk register:**
|
|
38
|
+
| Severity | Risk | Mitigation |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| High | `mcp_warmup` automates Google Search on a logged-in account → account-level flagging, larger blast radius than the Flow WAF | **Drop it** (Phase 4 re-evaluation only; not adopted). Replace with the direct `labs.google` navigation already present. |
|
|
41
|
+
| High | Un-gated `create_project` REST→UI rewrite = 10–30× hot-path regression (5–12 s/call, 135 s worst case) on every engine; DOM selector leaks into the API-client layer | **Do not adopt as-is.** REST stays the default `FlowApiClient.create_project`. A UI-first variant, if ever needed, lands transport-side + camoufox-gated (Phase 4). |
|
|
42
|
+
| High | MCP `_SessionManager` idle-reaper can `__aexit__` a client mid-generation (>5 min) — live concurrency bug | Deferred to Phase 4; needs in-use refcounting before any MCP session-caching lands. Not required for Phases 1–3. |
|
|
43
|
+
| Medium | Camoufox unverified vs live reCAPTCHA-Enterprise; Firefox-on-Flow is population-anomalous; engine-switch on a Chrome-authed profile silently fails | Phase 2 spike + Phase 3 profile↔engine mismatch guard + clean fresh-profile live verification. |
|
|
44
|
+
| Medium | Camoufox = third-party Firefox build with full live-session-cookie access (supply-chain trust); dep unpinned vs patchright exact-pin policy | Phase 3: pin exact version, document under SECURITY.md "elevated supply-chain trust", opt-in only. |
|
|
45
|
+
| Medium | `ref_names` invariant reversal (PR #245 image-i2i guard) rides in un-gated on the default path | Deferred to Phase 4; evaluate on its own with tests. Phase 1's i2i fix is the *other*, safe change (remote-UUID ref resolution). |
|
|
46
|
+
| Low | `image upscale` still mints via enterprise.js → likely broken under Camoufox | Phase 3: document the limitation or route the mint through the quirks gate. |
|
|
47
|
+
| Low | reCAPTCHA token-skip changes the default-path request (empty token) | **Safe** (Security-confirmed: ui_automation discards the minted token; Flow's JS mints natively on submit). Lands in Phase 3 re-expressed as a transport capability, with A/B evidence. |
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Provenance — PR #258 commit map
|
|
52
|
+
|
|
53
|
+
| SHA | Commit | Disposition |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `ad1d041` | Extract & save `display_name` for generated images | **Phase 1** — cherry-pick |
|
|
56
|
+
| `b94302c` | Resolve & attach remote-UUID refs in UI automation (i2i) | **Phase 1** — cherry-pick |
|
|
57
|
+
| `5f9d97e` | MCP video tool param parity + veo-lite i2v guard | **Phase 1** — cherry-pick (params + guard only) |
|
|
58
|
+
| `3a5a390` | Camoufox optional stealth engine | **Phase 3** — re-express through widened `_engine.py` |
|
|
59
|
+
| `85e67d3` | Camoufox WAF-retry + display_name tests | **Phase 3** (retry) / Phase 1 (display_name tests) |
|
|
60
|
+
| `c3254b4` | Re-attach refs during WAF retry | **Phase 3** — WAF retry hardening |
|
|
61
|
+
| `c8b8690` | Resource-picker auto-close detection | **Phase 3** — verify it's a real bug, not a Camoufox artifact |
|
|
62
|
+
| `741e44f` | `page.reload` → `goto(page.url)` (Camoufox timeout) | **Phase 4** — re-evaluate (default-path behavior change) |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## File structure
|
|
67
|
+
|
|
68
|
+
### New files
|
|
69
|
+
```
|
|
70
|
+
scripts/spike_waf_camoufox.py
|
|
71
|
+
Phase 2: A/B 403-rate harness — N generations per engine on one profile, compares
|
|
72
|
+
PUBLIC_ERROR_UNUSUAL_ACTIVITY / 403 rates. No product code.
|
|
73
|
+
docs/superpowers/spikes/2026-07-XX-camoufox-waf-403.md
|
|
74
|
+
Phase 2: the spike's recorded evidence (the ADR-13 gate artifact).
|
|
75
|
+
src/gflow_cli/auth/camoufox_strategy.py
|
|
76
|
+
Phase 3: AuthStrategy for `gflow auth login --browser camoufox` (re-expressed).
|
|
77
|
+
docs/LIVE_VERIFICATION_camoufox.md
|
|
78
|
+
Phase 3: 5-layer live ledger proving the Camoufox path evades the WAF end-to-end.
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Modified files
|
|
82
|
+
```
|
|
83
|
+
src/gflow_cli/api/dto.py Phase 1: display_name field on GeneratedImage.
|
|
84
|
+
src/gflow_cli/api/transports/ui_automation.py Phase 1: i2i remote-UUID ref resolution.
|
|
85
|
+
src/gflow_cli/mcp/tools.py Phase 1: gflow_generate_video model/duration/count + veo-lite i2v default.
|
|
86
|
+
src/gflow_cli/api/_engine.py Phase 3: widen to context-launcher adapter + EngineQuirks.
|
|
87
|
+
src/gflow_cli/config.py Phase 3: BrowserEngine.CAMOUFOX enum value.
|
|
88
|
+
src/gflow_cli/api/client.py Phase 3: engine dispatch via adapter; recaptcha-skip as transport capability.
|
|
89
|
+
src/gflow_cli/errors.py Phase 3: generalize BrowserEngineUnavailableError remediation.
|
|
90
|
+
pyproject.toml / uv.lock Phase 3: pinned [camoufox] extra.
|
|
91
|
+
.env.template / docs/CONFIGURATION.md / README.md / docs/KNOWN_ISSUES.md / SECURITY.md
|
|
92
|
+
Phase 3: engine docs, profile-mismatch caveat, supply-chain note.
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
# PHASE 1 — Quick wins (land now, no engine, contributor-credited)
|
|
98
|
+
|
|
99
|
+
> **Re-scoped 2026-07-09 after code investigation.** Two of the three planned cherry-picks
|
|
100
|
+
> evaporated on contact with develop — see the findings below. Phase 1's real deliverable is
|
|
101
|
+
> **one** genuine, safe, engine-independent improvement: MCP video param parity. Branch
|
|
102
|
+
> `fix/pr258-quick-wins` off `origin/develop`, `Co-authored-by: C1ph3r404`, one PR to develop.
|
|
103
|
+
|
|
104
|
+
## Task 1.1 — `display_name` — ALREADY SHIPPED (no work)
|
|
105
|
+
|
|
106
|
+
**Finding:** `GeneratedImage.display_name` + the `_workflow_display_names` parse + the recorder
|
|
107
|
+
`metadata_json` write are already on develop (commit `ec9377f`, shipped v0.26.0, credited to
|
|
108
|
+
C1ph3r404). PR #258's `ad1d041` is a duplicate of already-merged work. **Nothing to do.**
|
|
109
|
+
|
|
110
|
+
## Task 1.2 — i2i remote-UUID refs — MOVED TO PHASE 4 (not a safe quick win)
|
|
111
|
+
|
|
112
|
+
**Finding:** PR #258's only i2i commit (`b94302c`) IS the contested `ref_names` invariant
|
|
113
|
+
reversal, not a separable safe fix. It adds `ref_names` to `GenerateImageRequest` and **deletes
|
|
114
|
+
the PR #245 guard comment in `daemon.py`** ("image tasks … must not receive ref_names"),
|
|
115
|
+
routing image refs through the R2V `_attach_remote_references` mechanism. This is exactly the
|
|
116
|
+
default-image-path behavior change the Architect flagged. It needs its own predict + tests —
|
|
117
|
+
tracked as **Phase 4.3**, not Phase 1.
|
|
118
|
+
|
|
119
|
+
## Task 1.3 — MCP video param parity (the one genuine Phase 1 win) — ✅ DONE
|
|
120
|
+
|
|
121
|
+
**What:** Expose `model`/`duration`/`count` on `gflow_generate_video` (CLI↔MCP parity per the
|
|
122
|
+
AGENTS.md symmetry rule). The worker's `_build_video_request` already reads these payload keys;
|
|
123
|
+
the only gap was the MCP tool not accepting/forwarding them.
|
|
124
|
+
|
|
125
|
+
**Finding on the "veo-lite guard":** redundant. The transport (`ui_automation_video.py`, issue
|
|
126
|
+
#125) already defaults i2v-with-frames to `I2V_DEFAULT_MODEL` and raises
|
|
127
|
+
`ModelModeIncompatibilityError` for an explicit incompatible model — the MCP path inherits both.
|
|
128
|
+
So this task is parity + agent model-control, NOT a new credit guard.
|
|
129
|
+
|
|
130
|
+
**Files:** `src/gflow_cli/mcp/tools.py`, `tests/mcp/test_tools_wired.py`, `docs/MCP.md`, `CHANGELOG.md`.
|
|
131
|
+
|
|
132
|
+
**Steps:**
|
|
133
|
+
- [x] Add `model`/`duration`/`count` to the signature + docstring + tool description.
|
|
134
|
+
- [x] Validate the model alias up front → `_bad_param` 400 on unknown model (pre-spend, mirrors CLI).
|
|
135
|
+
- [x] Forward to payload; omit `model`/`duration` when unset so the transport's i2v default stands.
|
|
136
|
+
- [x] Echo the params in the result's `params` block.
|
|
137
|
+
|
|
138
|
+
**Tests created (red→green):**
|
|
139
|
+
- [x] `test_video_forwards_model_duration_count_to_payload`
|
|
140
|
+
- [x] `test_video_omits_unset_model_and_duration_from_payload` (transport default preserved)
|
|
141
|
+
- [x] `test_video_invalid_model_is_rejected_before_enqueue` — 400 before enqueue.
|
|
142
|
+
|
|
143
|
+
## Task 1.4 — Phase 1 gates + PR
|
|
144
|
+
|
|
145
|
+
**Steps:**
|
|
146
|
+
- [x] `/gflow:check` green (ruff / format / pyright / mcp+worker suites).
|
|
147
|
+
- [x] CHANGELOG `[Unreleased]` — Added entry crediting C1ph3r404.
|
|
148
|
+
- [ ] Open PR `fix/pr258-quick-wins → develop`, reference #258, wait for green CI + SonarCloud, merge.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
# PHASE 2 — WAF evidence spike (the ADR-13 gate)
|
|
153
|
+
|
|
154
|
+
**Blocking gate for Phase 3.** No product code. The ADR-13 question is not first "does
|
|
155
|
+
Camoufox win?" but "*is the current stealth stack actually insufficient?*" — so the spike's
|
|
156
|
+
first job is the **baseline**: measure the 403 rate on the default (playwright) engine. A
|
|
157
|
+
~0% baseline means ADR-13's premise is unmet → **STOP, Camoufox unjustified**, and no
|
|
158
|
+
Camoufox arm is ever needed. Only a materially non-zero baseline escalates to a Camoufox A/B.
|
|
159
|
+
|
|
160
|
+
**Sequencing note (why the arms are staged, not parallel):** `camoufox` is **not** a valid
|
|
161
|
+
`BrowserEngine` on develop — it is Phase 3, gated on this spike. So the spike **cannot** drive
|
|
162
|
+
a Camoufox arm through product code today (chicken-and-egg). This is correct: the baseline
|
|
163
|
+
comes first and may end the roadmap before any Camoufox code exists. The Camoufox A/B arm is
|
|
164
|
+
run *during Phase 3* (once the engine is wired) by re-running the same harness with
|
|
165
|
+
`--engine camoufox`.
|
|
166
|
+
|
|
167
|
+
## Task 2.1 — Spike harness — ✅ DONE
|
|
168
|
+
|
|
169
|
+
**What:** `scripts/spike_waf_camoufox.py` — drives N real image generations on one authed
|
|
170
|
+
profile through a chosen engine and classifies each outcome
|
|
171
|
+
(`success`/`waf_403`/`auth_401`/`rate_limited_429`/`other_error`); emits structured JSON
|
|
172
|
+
(per-attempt records + summary with `waf_403_rate`/`success_rate`).
|
|
173
|
+
|
|
174
|
+
**Files:** `scripts/spike_waf_camoufox.py` (scripts/ — excluded from SonarCloud; not imported
|
|
175
|
+
by the package).
|
|
176
|
+
|
|
177
|
+
**Steps:**
|
|
178
|
+
- [x] Engine-parameterized (`--engine playwright|patchright`); selects via `GFLOW_CLI_BROWSER_ENGINE`
|
|
179
|
+
+ `reset_settings()`, exactly as a user would.
|
|
180
|
+
- [x] `--engine camoufox` fails fast (exit 3) with the ADR-13 "measure the baseline first" pointer.
|
|
181
|
+
- [x] Credit-safe by default: `--dry-run` (validate + estimate, spend nothing) and an explicit
|
|
182
|
+
`--yes`/interactive confirmation gate; non-interactive without `--yes` refuses to spend.
|
|
183
|
+
- [x] Classifies `WafRejectionError`→403, `AuthExpiredError`→401 (aborts early — a dead session
|
|
184
|
+
dilutes the 403 rate), `RateLimitError`→429; `--delay` between attempts avoids self-inflicted 429s.
|
|
185
|
+
- [x] Ruff clean; dry-run + both guard exit codes verified without spending.
|
|
186
|
+
|
|
187
|
+
## Task 2.2 — Run the baseline + record the evidence — ✅ DONE (STOP verdict)
|
|
188
|
+
|
|
189
|
+
**What:** Ran the baseline arm; wrote the ADR-13 evidence artifact.
|
|
190
|
+
|
|
191
|
+
**Result (2026-07-09):** 20-gen baseline on `ffroliva` through the default stealth stack →
|
|
192
|
+
**0.0% WAF 403 rate** (19/20 success; the one miss was a `TransportTimeoutError` UI-scrape
|
|
193
|
+
flake, not a WAF block). Evidence: [../../spikes/2026-07-09-camoufox-waf-403.md](../../spikes/2026-07-09-camoufox-waf-403.md).
|
|
194
|
+
|
|
195
|
+
**Verdict: STOP.** The current stealth fix is confirmed sufficient — ADR-13's "confirm
|
|
196
|
+
insufficient before implementing" gate is unmet. ADR-13 (PLAN.md Decision Log #13) updated
|
|
197
|
+
with the evidence. Phase 1 stays shipped; **Phase 3 is NOT built.**
|
|
198
|
+
|
|
199
|
+
- [x] Baseline run (≈20 Imagen credits; a first attempt aborted at 0 credits on an expired
|
|
200
|
+
session, which validated the harness's clean expired-session handling).
|
|
201
|
+
- [x] Recorded raw JSON + the 403 rate.
|
|
202
|
+
- [x] Verdict applied: ~0% → STOP; ADR-13 updated; roadmap closed at Phase 2.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
# PHASE 3 — Camoufox engine adoption — ❌ NOT PROCEEDING (Phase 2 = STOP)
|
|
207
|
+
|
|
208
|
+
**Gate closed 2026-07-09.** The Phase 2 baseline showed a 0.0% WAF 403 rate, so per ADR-13 the
|
|
209
|
+
Camoufox engine is **not built**. The tasks below are retained only as the design of record in
|
|
210
|
+
case a future, repeatable WAF-403 reopens the gate (re-run `scripts/spike_waf_camoufox.py`;
|
|
211
|
+
a materially non-zero rate would revive this phase). Until then, none of it is implemented.
|
|
212
|
+
|
|
213
|
+
Re-expressed from PR #258 through the widened abstraction so engine logic lives in one place.
|
|
214
|
+
Own branch `feature/camoufox-engine → develop`, contributor-credited.
|
|
215
|
+
|
|
216
|
+
## Task 3.1 — Widen `_engine.py` + `EngineQuirks` (test scaffold)
|
|
217
|
+
|
|
218
|
+
**What:** Red tests for a single `open_persistent_context(engine, *, user_data_dir, headless,
|
|
219
|
+
chromium_kwargs) -> (BrowserContext, aclose)` adapter and an `EngineQuirks` value
|
|
220
|
+
(`typing_strategy`, `supports_init_script`, `needs_webdriver_patch`, `mints_recaptcha_inline`,
|
|
221
|
+
`mint_isolated_context`).
|
|
222
|
+
|
|
223
|
+
**Files:** `tests/api/test_engine.py`.
|
|
224
|
+
|
|
225
|
+
**Steps:**
|
|
226
|
+
- [ ] Tests: each engine resolves the right quirks; playwright/patchright quirks unchanged.
|
|
227
|
+
|
|
228
|
+
**Tests created (red):**
|
|
229
|
+
- [ ] `test_quirks_for_playwright_default` · `test_quirks_for_camoufox` · `test_adapter_returns_context_and_aclose`.
|
|
230
|
+
|
|
231
|
+
## Task 3.2 — Implement the adapter + quirks (green)
|
|
232
|
+
|
|
233
|
+
**What:** Fold the three PR #258 camoufox launch/teardown copies (auth, client, transport)
|
|
234
|
+
into one adapter; the CM-vs-driver asymmetry stays inside `_engine.py`. Add
|
|
235
|
+
`BrowserEngine.CAMOUFOX`, the pinned `[camoufox]` extra, `retryable_engine_errors()` extension.
|
|
236
|
+
|
|
237
|
+
**Files:** `src/gflow_cli/api/_engine.py`, `config.py`, `pyproject.toml`, `uv.lock`.
|
|
238
|
+
|
|
239
|
+
**Steps:**
|
|
240
|
+
- [ ] One adapter call at each site; delete inline `settings.browser_engine ==` checks in
|
|
241
|
+
`agentic.py` (~310) and `ui_automation.py` (~1277, ~1337) — replace with threaded quirks.
|
|
242
|
+
- [ ] Pin `camoufox==<exact>`; regenerate `uv.lock`.
|
|
243
|
+
- [ ] Partial-setup leak guard covers `AsyncCamoufox.__aenter__` failure (no orphaned firefox.exe,
|
|
244
|
+
no locked profile dir) — **must have a test** (Performance finding #4).
|
|
245
|
+
|
|
246
|
+
**Tests:** 3.1 green + a leak-guard test.
|
|
247
|
+
|
|
248
|
+
## Task 3.3 — Auth strategy + profile↔engine mismatch guard
|
|
249
|
+
|
|
250
|
+
**What:** Re-express `camoufox_strategy.py`; raise `BrowserEngineUnavailableError` (exit 24,
|
|
251
|
+
**not** the PR's `ConfigurationError`/exit 11) for a missing package **and** a missing
|
|
252
|
+
`camoufox fetch` binary. Add the mismatch guard: a camoufox-authed profile opened under a
|
|
253
|
+
chromium engine (or vice-versa) fails fast with a typed error, not the exit-8 login loop.
|
|
254
|
+
|
|
255
|
+
**Files:** `src/gflow_cli/auth/camoufox_strategy.py`, `src/gflow_cli/errors.py`, engine-resolution site.
|
|
256
|
+
|
|
257
|
+
**Steps:**
|
|
258
|
+
- [ ] Unify the missing-package exit code to 24 across auth + client paths.
|
|
259
|
+
- [ ] Catch missing-binary at `AsyncCamoufox` launch → exit 24 with a `camoufox fetch` hint
|
|
260
|
+
(verify camoufox-py's actual behavior first — CLI-UX must-test).
|
|
261
|
+
- [ ] Mismatch guard: read `.gflow_browser_strategy` marker; typed error on engine mismatch.
|
|
262
|
+
|
|
263
|
+
**Tests created (red):**
|
|
264
|
+
- [ ] `test_camoufox_missing_package_is_exit_24` · `test_camoufox_missing_binary_is_typed` ·
|
|
265
|
+
`test_profile_engine_mismatch_fails_fast` — all Critical.
|
|
266
|
+
|
|
267
|
+
## Task 3.4 — reCAPTCHA-skip + WAF-retry as transport capabilities
|
|
268
|
+
|
|
269
|
+
**What:** Re-express the (safe) empty-token path as `transport.mints_recaptcha_inline` on the
|
|
270
|
+
transport protocol (not a stringly `name == "ui_automation"` check); port the WAF-retry
|
|
271
|
+
ref-re-attach (`c3254b4`) and the resource-picker auto-close (`c8b8690`, only if confirmed a
|
|
272
|
+
real bug). Selectors follow the v0.29.0 canonical-source rule (`drivers/factory.py`), not new
|
|
273
|
+
hardcoded ligatures.
|
|
274
|
+
|
|
275
|
+
**Files:** `src/gflow_cli/api/transports/base.py`, `client.py`, `ui_automation.py`, `drivers/factory.py`.
|
|
276
|
+
|
|
277
|
+
**Tests created (red):**
|
|
278
|
+
- [ ] `test_ui_automation_mints_recaptcha_inline_capability` · WAF-retry ref-reattach test.
|
|
279
|
+
|
|
280
|
+
## Task 3.5 — Docs + live verification
|
|
281
|
+
|
|
282
|
+
**Files:** `.env.template`, `docs/CONFIGURATION.md`, `README.md`, `docs/KNOWN_ISSUES.md`,
|
|
283
|
+
`SECURITY.md`, `docs/USAGE.md`, `docs/LIVE_VERIFICATION_camoufox.md`.
|
|
284
|
+
|
|
285
|
+
**Steps:**
|
|
286
|
+
- [ ] `.env.template` + CONFIGURATION: `GFLOW_CLI_BROWSER_ENGINE` → `playwright | patchright | camoufox`;
|
|
287
|
+
install + `camoufox fetch`; "must match the engine you logged in with"; Windows binary-cache location.
|
|
288
|
+
- [ ] SECURITY.md: camoufox under "elevated supply-chain trust", exact-pinned.
|
|
289
|
+
- [ ] KNOWN_ISSUES: profile↔engine mismatch symptom; `image upscale` enterprise.js limitation under camoufox.
|
|
290
|
+
- [ ] README: engine mention + C1ph3r404 credit line.
|
|
291
|
+
- [ ] `docs/LIVE_VERIFICATION_camoufox.md`: full fresh-profile `auth login → create_project →
|
|
292
|
+
t2i → batch` under camoufox (5-layer ledger), session persistence across restart, the
|
|
293
|
+
Phase 2 403-rate delta, and the DevTools native-token confirmation.
|
|
294
|
+
|
|
295
|
+
## Task 3.6 — Phase 3 gates + PR
|
|
296
|
+
|
|
297
|
+
**Steps:**
|
|
298
|
+
- [ ] `/gflow:check` green; `/gflow:doc-review` clean.
|
|
299
|
+
- [ ] CHANGELOG `[Unreleased]` — Camoufox engine (opt-in), crediting C1ph3r404.
|
|
300
|
+
- [ ] PR `feature/camoufox-engine → develop`, reference #258, green CI + SonarCloud, merge.
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
# PHASE 4 — Deferred re-evaluations (each its own predict → plan)
|
|
305
|
+
|
|
306
|
+
Not adopted from PR #258; each needs independent design + evidence. Tracked here so nothing is
|
|
307
|
+
silently dropped. **Do not bundle these into Phases 1–3.**
|
|
308
|
+
|
|
309
|
+
- **4.1 — Transport-side UI-first `create_project`.** ARCHITECTURE.md already sanctions UI-first
|
|
310
|
+
creation *in the transport*. If a WAF-fallback for create is ever justified: REST-first, UI
|
|
311
|
+
fallback only on a WAF-classified failure, selector via `drivers/factory.py`, camoufox-gated.
|
|
312
|
+
Never in the API-client layer. (Blocked on a real need — createProject returns 200 today.)
|
|
313
|
+
- **4.2 — `mcp_warmup` redesign or removal.** As-is it automates Google Search on a logged-in
|
|
314
|
+
account (account-level risk). If any warmup is needed: direct `labs.google` navigation, own
|
|
315
|
+
env flag defaulted OFF, rate-limited, hard-stop (not swallow) on a Google captcha.
|
|
316
|
+
- **4.3 — i2i remote-UUID refs / `ref_names` invariant reversal** (PR #258 `b94302c`) —
|
|
317
|
+
**INVESTIGATED 2026-07-09: NOT A BUG on develop. Closed, no change needed.** The contributor's
|
|
318
|
+
premise ("i2i with a bare UUID ref is ignored → plain t2i submitted") does not reproduce:
|
|
319
|
+
develop attaches UUID refs via the v0.26.0 select-in-place path (`ui_automation.py:2175`
|
|
320
|
+
`if request.refs → _attach_image_uuid_refs`), which selects the existing Flow asset in the
|
|
321
|
+
picker, falls back to local-file upload, and **fails loud** if neither works — never a silent
|
|
322
|
+
drop. The PR's `ref_names` change would have added a SECOND, parallel R2V attach path on top,
|
|
323
|
+
likely double-attaching — good that it wasn't merged. Root cause of the false premise: a stale
|
|
324
|
+
`cli_image.py` comment claiming UUID binding was "not wired yet" (fixed). The PR #245 invariant
|
|
325
|
+
stands.
|
|
326
|
+
- **4.4 — MCP `_SessionManager` client caching + idle reaper.** The idle monitor can close a
|
|
327
|
+
client mid-generation. Needs in-use refcounting in the worker/service layer before any
|
|
328
|
+
session-caching lands.
|
|
329
|
+
- **4.5 — `.type()` chunked-input follow-up** for long agentic prompts under camoufox
|
|
330
|
+
(10–60 s per prompt) — a perf polish once the engine is in.
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## Definition of done (per phase)
|
|
335
|
+
|
|
336
|
+
- [ ] All in-phase task steps checked off.
|
|
337
|
+
- [ ] `/gflow:check` green (ruff / format / pyright / pytest ≥ 80% coverage).
|
|
338
|
+
- [ ] `CHANGELOG.md` `[Unreleased]` updated; contributor credit preserved.
|
|
339
|
+
- [ ] Docs updated (Phase 3: CONFIGURATION / SECURITY / KNOWN_ISSUES / README / live-verification).
|
|
340
|
+
- [ ] Phase 2 evidence recorded before any Phase 3 code merges (ADR-13 gate).
|
|
341
|
+
- [ ] No `# TODO` in diff without a tracked issue link.
|
|
342
|
+
- [ ] Each phase merges as its own PR referencing #258 for provenance.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Spike evidence — Camoufox WAF 403 baseline (ADR-13 gate)
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-07-09 · **Verdict: STOP — do not build the Camoufox engine (roadmap Phase 3).**
|
|
4
|
+
|
|
5
|
+
This is the ADR-13 evidence artifact for the
|
|
6
|
+
[camoufox-adoption roadmap](../plans/2026-07-09-camoufox-adoption/PLAN.md). ADR-13
|
|
7
|
+
(PLAN.md Decision Log #13 + the CDP-Attach backlog) parks every stealth-engine
|
|
8
|
+
alternative "until the stealth-flag fix is **confirmed insufficient** — this must be
|
|
9
|
+
verified before implementing anything." This spike ran that verification and the current
|
|
10
|
+
stealth stack is **confirmed sufficient**: zero WAF rejections over a real 20-generation
|
|
11
|
+
baseline. The premise for adopting Camoufox is therefore unmet.
|
|
12
|
+
|
|
13
|
+
## Method
|
|
14
|
+
|
|
15
|
+
`scripts/spike_waf_camoufox.py --engine playwright -n 20 --profile ffroliva` — 20 real
|
|
16
|
+
Imagen image generations against live Flow on one authenticated profile, through the
|
|
17
|
+
**default** stealth stack (Playwright + system Chrome `channel=chrome` +
|
|
18
|
+
`--disable-blink-features=AutomationControlled` + the `navigator.webdriver` init script).
|
|
19
|
+
Each attempt is classified: `success` / `waf_403` (`WafRejectionError`, the WAF/reCAPTCHA
|
|
20
|
+
wall) / `auth_401` / `rate_limited_429` / `other_error`.
|
|
21
|
+
|
|
22
|
+
- **Engine:** `playwright` (the baseline / default). Camoufox was **not** run — it is not a
|
|
23
|
+
drivable engine on develop (it *is* Phase 3, gated on this spike), and the baseline result
|
|
24
|
+
makes a Camoufox comparison moot.
|
|
25
|
+
- **Profile:** `ffroliva` (re-authenticated immediately before the run — a first attempt
|
|
26
|
+
aborted cleanly at 0 credits on an expired session, which validated the harness's
|
|
27
|
+
expired-session handling).
|
|
28
|
+
- **Model/aspect:** `narwhal` / `1:1`. **Window:** 2026-07-09 20:07–20:14 UTC (442.9s).
|
|
29
|
+
- **Raw evidence:** `scripts/dev/_spike_out/waf_spike_20260709_211430.json` (gitignored;
|
|
30
|
+
per-attempt records + summary).
|
|
31
|
+
|
|
32
|
+
## Result
|
|
33
|
+
|
|
34
|
+
| Outcome | Count |
|
|
35
|
+
|---|---|
|
|
36
|
+
| success | 19 |
|
|
37
|
+
| **WAF 403 (`WafRejectionError`)** | **0** |
|
|
38
|
+
| auth 401 | 0 |
|
|
39
|
+
| rate-limit 429 | 0 |
|
|
40
|
+
| other error | 1 |
|
|
41
|
+
| **WAF 403 rate** | **0.0%** |
|
|
42
|
+
| success rate | 95.0% |
|
|
43
|
+
|
|
44
|
+
Success latency: n=19, avg 10.5s (min 3.4s, max 34.6s).
|
|
45
|
+
|
|
46
|
+
The single non-success (attempt #3) was a `TransportTimeoutError` — "Agentic DOM scraping
|
|
47
|
+
timed out after 180s: 0/1 distinct media UUIDs appeared". That is a UI-cohort scraping
|
|
48
|
+
flake (the session bound the agentic cohort on that attempt), **not** a WAF block. It is
|
|
49
|
+
orthogonal to the stealth question and does not count toward the 403 rate.
|
|
50
|
+
|
|
51
|
+
## Interpretation
|
|
52
|
+
|
|
53
|
+
The historical 403 (`PUBLIC_ERROR_UNUSUAL_ACTIVITY`) that motivated the CDP-Attach / stealth
|
|
54
|
+
backlog was observed before the current stealth flags landed, when `navigator.webdriver=true`
|
|
55
|
+
let reCAPTCHA-Enterprise detect automation. This run — on the current stealth stack — produced
|
|
56
|
+
**zero** WAF rejections in 20 consecutive real generations. The stealth fix works; the WAF is
|
|
57
|
+
not a material problem for this configuration today.
|
|
58
|
+
|
|
59
|
+
**Sample-size honesty:** 0/20 is strong evidence that the WAF is *not currently* a material
|
|
60
|
+
blocker, not a proof of 0% under all conditions (WAF scoring varies with profile age, IP
|
|
61
|
+
reputation, request volume, and time). But the ADR-13 gate does not ask for a universal
|
|
62
|
+
guarantee — it asks whether the current fix is *insufficient*. This run decisively fails to
|
|
63
|
+
reproduce insufficiency. If a real, repeatable WAF-403 problem is later observed on the
|
|
64
|
+
default stack, re-run this spike to quantify it; a materially non-zero rate would reopen the
|
|
65
|
+
Camoufox question with the A/B arm.
|
|
66
|
+
|
|
67
|
+
## Decision
|
|
68
|
+
|
|
69
|
+
- **STOP the Camoufox adoption roadmap at Phase 2.** Do not build the engine (Phase 3).
|
|
70
|
+
- **Phase 1 stays shipped** (PR #273 — MCP video param parity; unrelated to the engine).
|
|
71
|
+
- **ADR-13 updated** (PLAN.md Decision Log #13) with this evidence: the stealth-flag fix is
|
|
72
|
+
confirmed sufficient as of 2026-07-09; CDP-Attach and Camoufox remain parked.
|
|
73
|
+
- **Phase 4 items** (transport-side UI-first create_project, `mcp_warmup`, the i2i `ref_names`
|
|
74
|
+
invariant, the MCP `_SessionManager` idle-reaper concurrency fix) were always independent of
|
|
75
|
+
the engine and remain as their own backlog — each needs its own predict if picked up.
|