gflow-cli 0.10.0__tar.gz → 0.12.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.10.0 → gflow_cli-0.12.0}/.claude/README.md +4 -1
- gflow_cli-0.12.0/.claude/commands/gflow/active.md +13 -0
- gflow_cli-0.12.0/.claude/commands/gflow/next.md +12 -0
- gflow_cli-0.12.0/.claude/commands/gflow/plan.md +22 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.claude/commands/gflow/predict.md +7 -1
- gflow_cli-0.12.0/.claude/commands/gflow/release.md +241 -0
- gflow_cli-0.12.0/.claude/commands/gflow/status.md +12 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.gitignore +6 -0
- gflow_cli-0.12.0/.planning/issue-125-fix.md +207 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/AGENTS.md +22 -4
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/CHANGELOG.md +150 -1
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/CLAUDE.md +17 -2
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/GEMINI.md +3 -2
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/KNOWN_ISSUES.md +116 -10
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/PKG-INFO +12 -2
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/PLAN.md +2 -2
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/README.md +7 -1
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/AGENT_GUIDE.md +12 -1
- gflow_cli-0.12.0/docs/CHARACTER.md +506 -0
- gflow_cli-0.12.0/docs/CHARACTER_RECON.md +147 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/CONFIGURATION.md +35 -0
- gflow_cli-0.12.0/docs/DEMOS.md +47 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/INDEX.md +17 -3
- gflow_cli-0.12.0/docs/LIVE_VERIFICATION_v0.11.0.md +100 -0
- gflow_cli-0.12.0/docs/LIVE_VERIFICATION_v0.12.0.md +83 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/PROJECT_STATUS.md +9 -2
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/USAGE.md +248 -0
- gflow_cli-0.12.0/docs/assets/demo-split-pf.gif +0 -0
- gflow_cli-0.12.0/docs/superpowers/character-scenario.md +140 -0
- gflow_cli-0.12.0/docs/superpowers/plans/2026-05-30-l0-sapisidhash-aisandbox-auth.md +697 -0
- gflow_cli-0.12.0/docs/superpowers/plans/2026-05-31-l0-bearer-pivot.md +97 -0
- gflow_cli-0.12.0/docs/superpowers/plans/2026-05-31-l1-scene-compose.md +1480 -0
- gflow_cli-0.12.0/docs/superpowers/plans/2026-05-31-scene-concat-extend.md +100 -0
- gflow_cli-0.12.0/docs/superpowers/plans/2026-06-02-character-creation-phase2.md +293 -0
- gflow_cli-0.12.0/docs/superpowers/plans/2026-06-02-character-creation.md +300 -0
- gflow_cli-0.12.0/docs/superpowers/specs/2026-05-30-add-clip-scene-timeline-design.md +195 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/examples/README.md +4 -0
- gflow_cli-0.12.0/examples/workflow_chain.py +314 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/llms.txt +2 -1
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/pyproject.toml +14 -1
- gflow_cli-0.12.0/samples/captured/12_create_scene.json +6 -0
- gflow_cli-0.12.0/samples/captured/13_sceneWorkflows_update.json +6 -0
- gflow_cli-0.12.0/samples/captured/14_get_scene_workflows.json +6 -0
- gflow_cli-0.12.0/samples/captured/15_commit_flowWorkflow.json +6 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/ci/check_doc_links.py +1 -0
- gflow_cli-0.12.0/scripts/dev/_spike_common.py +111 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/dev/active_plan.py +1 -1
- gflow_cli-0.12.0/scripts/dev/capture_i2v_intercept_submit.py +262 -0
- gflow_cli-0.12.0/scripts/dev/capture_i2v_model_select_repro.py +104 -0
- gflow_cli-0.12.0/scripts/dev/capture_i2v_post_bind_state.py +288 -0
- gflow_cli-0.12.0/scripts/dev/character_create_spike.py +344 -0
- gflow_cli-0.12.0/scripts/dev/character_create_spike_v2.py +499 -0
- gflow_cli-0.12.0/scripts/dev/dump_character_selectors.js +74 -0
- gflow_cli-0.12.0/scripts/dev/skillopt/README.md +106 -0
- gflow_cli-0.12.0/scripts/dev/skillopt/harness.py +365 -0
- gflow_cli-0.12.0/scripts/dev/skillopt/tasks.json +242 -0
- gflow_cli-0.12.0/scripts/dev/spike_char_editor_dom.py +237 -0
- gflow_cli-0.12.0/scripts/dev/spike_char_gen_capture.py +349 -0
- gflow_cli-0.12.0/scripts/dev/spike_patch_entity.py +244 -0
- gflow_cli-0.12.0/skills/README.md +76 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/skills/gflow-cli/SKILL.md +80 -1
- gflow_cli-0.12.0/skills/plan/SKILL.md +215 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/skills/pr-council-review/SKILL.md +1 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/skills/predict/SKILL.md +1 -0
- gflow_cli-0.12.0/skills/status/SKILL.md +99 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/__init__.py +1 -1
- gflow_cli-0.12.0/src/gflow_cli/api/_sapisidhash.py +15 -0
- gflow_cli-0.12.0/src/gflow_cli/api/character.py +261 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/client.py +647 -18
- gflow_cli-0.12.0/src/gflow_cli/api/routes.py +132 -0
- gflow_cli-0.12.0/src/gflow_cli/api/scene.py +172 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/transports/experimental/sapisidhash.py +1 -8
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/transports/ui_automation.py +553 -55
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/transports/ui_automation_video.py +357 -26
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/video.py +23 -0
- gflow_cli-0.12.0/src/gflow_cli/chain.py +307 -0
- gflow_cli-0.12.0/src/gflow_cli/chain_manifest.py +138 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/cli.py +4 -0
- gflow_cli-0.12.0/src/gflow_cli/cli_character.py +379 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/cli_data.py +6 -3
- gflow_cli-0.12.0/src/gflow_cli/cli_scene.py +239 -0
- gflow_cli-0.12.0/src/gflow_cli/cli_video.py +1030 -0
- gflow_cli-0.12.0/src/gflow_cli/data/chain_repo.py +128 -0
- gflow_cli-0.12.0/src/gflow_cli/data/migrations/0003_add_scene_tables.sql +29 -0
- gflow_cli-0.12.0/src/gflow_cli/data/migrations/0004_add_scene_output_path.sql +5 -0
- gflow_cli-0.12.0/src/gflow_cli/data/migrations/0005_add_chain_links.sql +27 -0
- gflow_cli-0.12.0/src/gflow_cli/data/migrations/0006_add_operations_metadata.sql +5 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/data/models.py +53 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/data/recorder.py +324 -21
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/data/repository.py +330 -4
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/errors.py +184 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/json_output.py +13 -2
- gflow_cli-0.12.0/src/gflow_cli/media.py +120 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/paths.py +21 -0
- gflow_cli-0.12.0/src/gflow_cli/services/__init__.py +6 -0
- gflow_cli-0.12.0/src/gflow_cli/services/character_create.py +299 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tasks/lessons.md +1 -1
- gflow_cli-0.12.0/tests/api/fixtures/character_gen_response.json +54 -0
- gflow_cli-0.12.0/tests/api/fixtures/patch_entity_response.json +13 -0
- gflow_cli-0.12.0/tests/api/test_aisandbox_auth_error.py +25 -0
- gflow_cli-0.12.0/tests/api/test_aisandbox_auth_headers.py +120 -0
- gflow_cli-0.12.0/tests/api/test_bearer_redaction.py +74 -0
- gflow_cli-0.12.0/tests/api/test_character.py +402 -0
- gflow_cli-0.12.0/tests/api/test_client_character.py +307 -0
- gflow_cli-0.12.0/tests/api/test_client_generate_character.py +429 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/test_client_image.py +5 -5
- gflow_cli-0.12.0/tests/api/test_client_patch_entity.py +158 -0
- gflow_cli-0.12.0/tests/api/test_client_scene.py +241 -0
- gflow_cli-0.12.0/tests/api/test_post_json_aisandbox_auth.py +131 -0
- gflow_cli-0.12.0/tests/api/test_routes_character.py +20 -0
- gflow_cli-0.12.0/tests/api/test_routes_scene.py +47 -0
- gflow_cli-0.12.0/tests/api/test_sapisidhash_helper.py +14 -0
- gflow_cli-0.12.0/tests/api/test_scene_models.py +120 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/test_video.py +24 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/transports/test_ui_automation.py +521 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/transports/test_ui_automation_video.py +290 -2
- gflow_cli-0.12.0/tests/api/transports/test_ui_character_editor.py +912 -0
- gflow_cli-0.12.0/tests/cli/test_cli_character.py +275 -0
- gflow_cli-0.12.0/tests/cli/test_cli_character_create.py +613 -0
- gflow_cli-0.12.0/tests/cli/test_cli_scene.py +160 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/cli/test_cli_video.py +107 -0
- gflow_cli-0.12.0/tests/cli/test_cli_video_chain.py +373 -0
- gflow_cli-0.12.0/tests/data/test_chain_repo.py +221 -0
- gflow_cli-0.12.0/tests/data/test_find_incomplete_character.py +217 -0
- gflow_cli-0.12.0/tests/data/test_models.py +24 -0
- gflow_cli-0.12.0/tests/data/test_recorder_character.py +254 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/data/test_repository.py +66 -10
- gflow_cli-0.12.0/tests/data/test_scene_persistence.py +148 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/data/test_store_migrations.py +1 -1
- gflow_cli-0.12.0/tests/e2e/test_aisandbox_auth_live.py +72 -0
- gflow_cli-0.12.0/tests/e2e/test_chain_e2e.py +198 -0
- gflow_cli-0.12.0/tests/e2e/test_character_create_e2e.py +442 -0
- gflow_cli-0.12.0/tests/e2e/test_scene_compose_live.py +103 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/e2e/test_transports_e2e.py +236 -2
- gflow_cli-0.12.0/tests/features/character_create.feature +34 -0
- gflow_cli-0.12.0/tests/features/character_read.feature +10 -0
- gflow_cli-0.12.0/tests/features/test_character_create_steps.py +288 -0
- gflow_cli-0.12.0/tests/features/test_character_read_steps.py +171 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/features/test_step_collision_guard.py +2 -0
- gflow_cli-0.12.0/tests/features/test_video_chain_steps.py +291 -0
- gflow_cli-0.12.0/tests/features/video_chain.feature +37 -0
- gflow_cli-0.12.0/tests/services/test_character_create_redaction.py +312 -0
- gflow_cli-0.12.0/tests/services/test_character_create_saga.py +442 -0
- gflow_cli-0.12.0/tests/services/test_character_gen_no_direct_post.py +243 -0
- gflow_cli-0.12.0/tests/smoke/__init__.py +0 -0
- gflow_cli-0.12.0/tests/test_chain.py +372 -0
- gflow_cli-0.12.0/tests/test_chain_manifest.py +243 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/test_errors.py +70 -0
- gflow_cli-0.12.0/tests/test_errors_403.py +19 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/test_marker_registry.py +1 -1
- gflow_cli-0.12.0/tests/test_media.py +158 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/test_paths.py +18 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/uv.lock +121 -2
- gflow_cli-0.10.0/.claude/commands/gflow/plan.md +0 -39
- gflow_cli-0.10.0/.claude/commands/gflow/release.md +0 -168
- gflow_cli-0.10.0/skills/README.md +0 -36
- gflow_cli-0.10.0/src/gflow_cli/api/routes.py +0 -64
- gflow_cli-0.10.0/src/gflow_cli/cli_video.py +0 -554
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.claude/commands/gflow/branch-review.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.claude/commands/gflow/changelog.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.claude/commands/gflow/check.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.claude/commands/gflow/doc-review.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.claude/commands/gflow/known-issues.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.claude/commands/gflow/pr-council-review.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.claude/commands/gflow/scenario.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.continue-here.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.env.template +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.gitattributes +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.github/CODEOWNERS +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.github/copilot-instructions.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.github/dependabot.yml +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.github/workflows/ci.yml +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.github/workflows/external-pr-triage.yml +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.github/workflows/release.yml +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.gitleaks.toml +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.planning/todos/pending/2026-05-11-add-project-logo-and-docs-site-promotion-plan.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.planning/todos/pending/pr-38-review.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.pre-commit-config.yaml +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/.secrets.baseline +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/CONFIGURATION.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/CONTRIBUTING.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/DISCLAIMER.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/LICENSE +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/RELEASE.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/ROADMAP.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/conftest.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docker-compose.yml +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/ARCHITECTURE.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/AUTHENTICATION.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/DATA_LAYER.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/DEBUGGING.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/DEVELOPMENT.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/E2E_TESTING.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/EXTERNAL_STORAGE.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/GITHUB.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/LIVE_VERIFICATION_data_layer.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/LIVE_VERIFICATION_image_batch.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/LIVE_VERIFICATION_v0.10.0.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/LIVE_VERIFICATION_v0.7.0.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/LIVE_VERIFICATION_v0.8.1.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/LIVE_VERIFICATION_v0.9.0.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/LIVE_VERIFICATION_v0.9.1.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/LIVE_VERIFICATION_video_download.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/SECURITY.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/USER_GUIDE.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/assets/example-run.gif +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/2026-05-17-issue-15-handover.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-09-image-mvp-orchestration.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-09-image-mvp.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-09-video-mvp-orchestration.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-09-video-mvp.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-10-phase-4-hardening-orchestration.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-10-phase-4-hardening.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/2026-05-14-shell-multi-prompt-orchestration.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_FINAL_ARCH.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_FINAL_SEC_UX.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_CODE.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_GEMINI.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_SECURITY.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/IMPLEMENTATION_REVIEW_PYTHON.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/IMPLEMENTATION_REVIEW_SECURITY.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_CODE.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_FOLLOWUP.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_PLANNER.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_SECURITY.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_SECURITY_FOLLOWUP.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/COUNCIL_FINAL_SEC_UX_VERIFIED.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/COUNCIL_REVIEW_PLAN_SECURITY.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/COUNCIL_REVIEW_SPEC_SECURITY.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/PLAN.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/orchestration.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-17-e2e-test-coverage.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-17-issue-15-auth-verification-fix.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-17-issue-15-i2v-bearer-auth.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-17-issue-15-orchestration.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-18-video-phase0-submit-spike.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-19-video-phase-a-execution-state.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-19-video-phase-a-orchestration.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-19-video-phase-a-t2v.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-20-video-download-t2v-cli.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-21-multi-image-prompt-orchestration.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-21-multi-image-prompt.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-22-pr-38-review.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-22-stay-mounted-batch-session-plan.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-23-locale-agnostic-selectors.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/plans/2026-05-24-data-layer.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/specs/2026-05-10-phase-4-hardening-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/specs/2026-05-14-shell-multi-prompt-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/specs/2026-05-15-auth-login-real-chrome-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/specs/2026-05-17-e2e-test-coverage-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/specs/2026-05-17-i2v-uploadimage-401-bearer-auth-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/specs/2026-05-17-issue-15-auth-verification-fix-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/specs/2026-05-17-issue-15-root-cause-findings.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/specs/2026-05-18-ui-automation-video-generation-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/specs/2026-05-21-multi-image-prompt-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/specs/2026-05-22-pr-38-review-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/specs/2026-05-22-stay-mounted-batch-session-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/specs/2026-05-23-locale-agnostic-selectors.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/specs/2026-05-23-readme-v0.8.1-refresh-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/specs/2026-05-24-data-layer-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/specs/2026-05-27-public-event-surface-design.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/docs/superpowers/verifications/2026-05-11-phase-4-stage-g.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/examples/batch_from_config.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/examples/multi_prompt_t2i.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/examples/sample_config.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/examples/sample_prompts.txt +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/examples/single_image_t2i.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/samples/README.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/samples/captured/01_upload_image.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/samples/captured/02_batchAsyncGenerateVideoText.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/samples/captured/04_archive_workflow.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/samples/captured/05_createProject.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/samples/captured/06_batchGenerateImages.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/samples/captured/07_batchGenerateImages_seeded.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/samples/captured/08_batchAsyncGenerateVideoStartAndEndImage.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/samples/captured/09_batchAsyncGenerateVideoReferenceImages.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/samples/captured/10_batchCheckAsyncVideoGenerationStatus_successful.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/samples/captured/11_batchCheckAsyncVideoGenerationStatus_failed.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/ci/check_repo_hygiene.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/debug_editor.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/debug_gen_settings.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/debug_settings.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/dev/capture_i2v_frame_slots_dom.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/dev/capture_image_add_media_dom.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/dev/capture_locale_invariants.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/dev/cdp_drive_and_probe.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/dev/monitor_pr_38.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/diag_capture_flow_traffic.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/diag_recaptcha_mint.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/record_demo.ps1 +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/smoke_image.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/smoke_real_chrome_image.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/smoke_video_editor.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/smoke_worker_style.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/scripts/verify_chrome_auth_viability.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/skills/scenario/SKILL.md +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/sonar-project.properties +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/__main__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/_cli_helpers.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/_retry.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/dto.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/image.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/recaptcha.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/transports/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/transports/_common.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/transports/_fingerprint.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/transports/base.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/transports/experimental/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/transports/experimental/bearer.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/api/transports/experimental/evaluate_fetch.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/auth/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/auth/base.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/auth/factory.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/auth/internal_chromium.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/auth/real_chrome.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/auth/strategies.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/auth/verification.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/browser_manager.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/cli_image.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/cli_models.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/cli_run.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/config.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/data/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/data/migrations/0001_initial.sql +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/data/migrations/0002_add_cloud_storage.sql +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/data/migrations/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/data/queries.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/data/redaction.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/data/store.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/exceptions.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/image_batch.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/manifest.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/observability.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/profile_store.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/src/gflow_cli/storage.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/test_assets/sample_batch.json +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/test_assets/sample_batch.tsv +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/test_assets/sample_batch_invalid.tsv +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/test_client.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/test_concurrency.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/test_dto.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/test_image.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/test_image_dto.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/test_recaptcha.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/test_retry.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/test_routes.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/transports/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/transports/test_base.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/transports/test_bearer.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/transports/test_common.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/transports/test_evaluate_fetch.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/transports/test_factory.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/transports/test_fingerprint.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/transports/test_sapisidhash.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/transports/test_transport_timeout.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/transports/test_ui_automation_batch.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/api/transports/test_ui_automation_image_mode.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/auth/strategies/test_factory.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/auth/strategies/test_strategies.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/auth/test_verification.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/cli/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/cli/test_cli_auth_list.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/cli/test_cli_data.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/cli/test_cli_image.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/cli/test_cli_image_seed_removed.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/cli/test_cli_models.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/cli/test_cli_run.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/cli/test_error_handling.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/cli/test_helpers.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/cli/test_t2i_multi_prompt.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/conftest.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/data/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/data/test_packaging.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/data/test_recorder.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/data/test_redaction.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/data/test_settings_and_errors.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/e2e/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/e2e/conftest.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/e2e/test_auth_verification_e2e.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/e2e/test_data_layer_e2e.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/e2e/test_image_batch_e2e.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/e2e/test_image_i2i_ref_cap_e2e.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/e2e/test_json_output_e2e.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/e2e/test_locale_selectors_e2e.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/e2e/test_video_r2v_ref_cap_e2e.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/e2e/test_video_t2v_e2e.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/features/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/features/auth.feature +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/features/auth_login.feature +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/features/conftest.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/features/image.feature +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/features/test_auth_login_steps.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/features/test_auth_steps.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/features/test_image_steps.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/fixtures/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/fixtures/seeded_catalog.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/image_batch/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/image_batch/test_image_manifest.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/image_batch/test_observability_events.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/integration/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/integration/conftest.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/integration/constants.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/integration/test_storage_gcs.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/integration/test_storage_s3.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/scripts/test_capture_locale_invariants.py +0 -0
- {gflow_cli-0.10.0/tests/smoke → gflow_cli-0.12.0/tests/services}/__init__.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/smoke/test_profile_account_smoke.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/smoke/test_real_flow.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/test_auth.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/test_browser_manager.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/test_cli_data.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/test_config.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/test_conftest_isolation.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/test_data_queries.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/test_documentation_gate.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/test_json_output.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/test_manifest.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/test_observability.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/test_profile_store.py +0 -0
- {gflow_cli-0.10.0 → gflow_cli-0.12.0}/tests/test_smoke.py +0 -0
|
@@ -12,7 +12,10 @@ This directory holds **internal maintainer workflows** that are bundled with the
|
|
|
12
12
|
└── commands/ ← repo-local slash commands
|
|
13
13
|
└── gflow/ ← `/gflow:*` namespace (avoids collision with built-ins)
|
|
14
14
|
├── check.md ← `/gflow:check` — hygiene + ruff + pyright + pytest
|
|
15
|
-
├──
|
|
15
|
+
├── status.md ← `/gflow:status` — full plan state (file, goal, progress, next task)
|
|
16
|
+
├── next.md ← `/gflow:next` — next unchecked task only
|
|
17
|
+
├── active.md ← `/gflow:active` — which plan is active, goal only
|
|
18
|
+
├── plan.md ← `/gflow:plan <feature>` — create a task-by-task implementation plan
|
|
16
19
|
├── known-issues.md← `/gflow:known-issues` — open/mitigated items
|
|
17
20
|
├── changelog.md ← `/gflow:changelog` — [Unreleased] + last tagged
|
|
18
21
|
└── release.md ← `/gflow:release` — full release flow (signed tags)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Show which plan is active and its goal — orientation without task detail.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# `/gflow:active` — Active plan identity
|
|
6
|
+
|
|
7
|
+
**Read `skills/status/SKILL.md` and follow the `active` variant protocol.**
|
|
8
|
+
|
|
9
|
+
> Do **not** call `Skill(skill="status")` — read the file directly.
|
|
10
|
+
|
|
11
|
+
The skill at `skills/status/SKILL.md` runs `scripts/dev/active_plan.py` and returns
|
|
12
|
+
only the header lines (Plan path, Title, Goal, Progress count). Stops before the
|
|
13
|
+
`--- Next task ---` separator.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Show only the next unchecked task — minimal output, no context noise.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# `/gflow:next [feature]` — Next task
|
|
6
|
+
|
|
7
|
+
**Read `skills/status/SKILL.md` and follow the `next` variant protocol**, passing `$ARGUMENTS` as the optional feature slug.
|
|
8
|
+
|
|
9
|
+
> Do **not** call `Skill(skill="status")` — read the file directly.
|
|
10
|
+
|
|
11
|
+
The skill at `skills/status/SKILL.md` runs `scripts/dev/active_plan.py` and returns
|
|
12
|
+
only the `--- Next task ---` block. Header lines (Plan, Title, Goal, Progress) are omitted.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Create a structured task-by-task implementation plan for a feature and write it to docs/superpowers/plans/.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# `/gflow:plan <feature>` — Create a feature plan
|
|
6
|
+
|
|
7
|
+
**Read `skills/plan/SKILL.md` and follow its protocol now**, passing `$ARGUMENTS` as the feature description.
|
|
8
|
+
|
|
9
|
+
> Do **not** call `Skill(skill="plan")` — the repo's `skills/*/SKILL.md` files are plain Markdown, not registered as Skill-tool-invocable. Read the file directly instead.
|
|
10
|
+
|
|
11
|
+
The skill at `skills/plan/SKILL.md` gathers predict/scenario context, asks ≤3
|
|
12
|
+
clarifying questions, decomposes the feature into atomic committable tasks with
|
|
13
|
+
step + test checklists, and writes `docs/superpowers/plans/<date>-<slug>/PLAN.md`.
|
|
14
|
+
|
|
15
|
+
**Typical workflow:**
|
|
16
|
+
```
|
|
17
|
+
/gflow:predict <proposal> → GO / CAUTION / STOP
|
|
18
|
+
/gflow:scenario <feature> → edge cases + BDD skeleton
|
|
19
|
+
/gflow:plan <feature> → writes PLAN.md ← this command
|
|
20
|
+
/gflow:status → surfaces next task
|
|
21
|
+
/gflow:check → before each commit
|
|
22
|
+
```
|
|
@@ -16,4 +16,10 @@ The skill at `skills/predict/SKILL.md` runs five independent expert personas
|
|
|
16
16
|
(Architect · Security/reCAPTCHA · Performance/Playwright · CLI UX · Devil's Advocate),
|
|
17
17
|
resolves conflicts, and returns a GO / CAUTION / STOP verdict with a confidence score.
|
|
18
18
|
|
|
19
|
-
**
|
|
19
|
+
**Typical workflow after a GO or CAUTION:**
|
|
20
|
+
```
|
|
21
|
+
/gflow:scenario <feature> → edge cases + BDD skeleton
|
|
22
|
+
/gflow:plan <feature> → writes PLAN.md task checklist
|
|
23
|
+
/gflow:status → surfaces next task during execution
|
|
24
|
+
/gflow:check → before each commit
|
|
25
|
+
```
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Cut a new gflow-cli release — bump version, update CHANGELOG, tag, push, and back-merge.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# `/gflow:release` — Cut a new release
|
|
6
|
+
|
|
7
|
+
Follow this sequence verbatim. Every step matters.
|
|
8
|
+
|
|
9
|
+
> **Branch-protection note:** `main` blocks direct pushes. The release commit travels
|
|
10
|
+
> via a `chore/release-vX.Y.Z` branch PR. The signed tag is pushed independently
|
|
11
|
+
> (tag pushes bypass branch protection and trigger the CI release workflow immediately).
|
|
12
|
+
>
|
|
13
|
+
> **Source-branch note (read first):** `develop` is the integration branch — it carries
|
|
14
|
+
> ALL unreleased work and `main` usually lags it. The release branch is cut from
|
|
15
|
+
> **`develop`**, NOT `main`. The PR `chore/release-vX.Y.Z → main` then brings the full
|
|
16
|
+
> integration history onto `main`. Do not expect the work to already be on `main`.
|
|
17
|
+
|
|
18
|
+
## Inputs
|
|
19
|
+
|
|
20
|
+
Ask the user (if not already provided):
|
|
21
|
+
|
|
22
|
+
1. **Version** — the new version (e.g. `0.4.0`, `0.4.0a3`, `1.0.0rc1`). Use PEP 440 prerelease suffixes (`aN`, `bN`, `rcN`). If they don't know, run `/gflow:changelog` first and propose the next bump (PATCH for fixes only, MINOR for new features, MAJOR for breaks).
|
|
23
|
+
2. **Pre-release?** — prerelease versions stay marked as GitHub prereleases. Only the user can say when a release line is ready for the stable tag.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Sequence
|
|
28
|
+
|
|
29
|
+
**1. Review what's queued.**
|
|
30
|
+
|
|
31
|
+
Run `/gflow:changelog` — confirm the `[Unreleased]` block is non-empty and accurate before proceeding.
|
|
32
|
+
|
|
33
|
+
**2. Verify (or triage) a clean working tree.**
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
git status --short
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
If empty, continue. If not, **triage before aborting** — do not blindly stop:
|
|
40
|
+
|
|
41
|
+
- **Auto-injected boilerplate** (e.g. a context-mode routing block appended to
|
|
42
|
+
`CLAUDE.md` by an MCP plugin's SessionStart hook): this is plugin-injected, not
|
|
43
|
+
project content — `git restore` it. Confirm with the user if unsure.
|
|
44
|
+
- **Build/temp artifacts** (e.g. a stray `tmp*.tar.gz` sdist at repo root): delete them.
|
|
45
|
+
- **Genuine uncommitted work:** STOP and tell the user to commit or stash on the
|
|
46
|
+
appropriate branch (never commit straight to `develop`).
|
|
47
|
+
|
|
48
|
+
The tree must be clean before you create the release branch.
|
|
49
|
+
|
|
50
|
+
**3. Verify `develop` is the release source and up-to-date.**
|
|
51
|
+
|
|
52
|
+
The release is cut from `develop`, NOT `main` (see Source-branch note above).
|
|
53
|
+
Confirm direction explicitly — a backwards divergence means a prior back-merge was skipped.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
git fetch origin
|
|
57
|
+
git rev-parse --abbrev-ref HEAD # expect "develop"
|
|
58
|
+
git rev-list --count HEAD..origin/develop # local behind origin — expect 0
|
|
59
|
+
git rev-list --count origin/main..origin/develop # develop AHEAD of main — expect > 0 (the work to release)
|
|
60
|
+
git rev-list --count origin/develop..origin/main # main AHEAD of develop — expect 0
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
If not on `develop`: `git checkout develop && git pull origin develop`.
|
|
64
|
+
If local is behind origin: `git pull origin develop`.
|
|
65
|
+
**If `main` is AHEAD of `develop` (last count > 0): STOP.** A prior release skipped its
|
|
66
|
+
`main → develop` back-merge — recover first (see the `release-back-merge-gap-recovery`
|
|
67
|
+
memory) or the release branch will hit conflicts on `pyproject.toml` / `__init__.py` / `CHANGELOG.md`.
|
|
68
|
+
|
|
69
|
+
**4. Run quality gates.**
|
|
70
|
+
|
|
71
|
+
Run `/gflow:check` — all gates must pass. Abort if any fail.
|
|
72
|
+
|
|
73
|
+
**5. Create a release branch off `develop`.**
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
git checkout develop # ensure the base is develop, not main
|
|
77
|
+
git checkout -b chore/release-v<NEW_VERSION>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
This branch now contains all of `develop` (⊇ `main`) plus your release prep. All
|
|
81
|
+
release prep commits live here; the PR into `main` (step 14) carries the full
|
|
82
|
+
integration history forward.
|
|
83
|
+
|
|
84
|
+
**6. Bump version** in `pyproject.toml`:
|
|
85
|
+
|
|
86
|
+
```toml
|
|
87
|
+
[project]
|
|
88
|
+
version = "<NEW_VERSION>"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**7. Bump package version** in `src/gflow_cli/__init__.py`:
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
__version__ = "<NEW_VERSION>"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**8. Update version assertion tests** if present:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
rg -n "__version__|<OLD_VERSION>|version assertion" tests src pyproject.toml
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**9. Migrate CHANGELOG.**
|
|
104
|
+
|
|
105
|
+
- Move all entries under `## [Unreleased]` to a new `## [<NEW_VERSION>] — YYYY-MM-DD` section.
|
|
106
|
+
- Leave `## [Unreleased]` empty.
|
|
107
|
+
- Update the link footer. Match the repo's existing convention — every prior entry
|
|
108
|
+
uses the `compare/vPREV...vNEW` form, so use that for the new version too (NOT the
|
|
109
|
+
`releases/tag/` form), or `/gflow:doc-review` will flag the inconsistency:
|
|
110
|
+
```
|
|
111
|
+
[Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v<NEW_VERSION>...HEAD
|
|
112
|
+
[<NEW_VERSION>]: https://github.com/ffroliva/gflow-cli/compare/v<PREV_VERSION>...v<NEW_VERSION>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**10. Run the documentation review gate.**
|
|
116
|
+
|
|
117
|
+
Run `/gflow:doc-review` — audit all version refs, INDEX completeness, evidence files, skill files, CHANGELOG footer, and memory files. Fix every **FAIL** before continuing. Fold all discovered fixes into the release prep commit.
|
|
118
|
+
|
|
119
|
+
**11. Commit the release prep.**
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
git add pyproject.toml src/gflow_cli/__init__.py uv.lock CHANGELOG.md
|
|
123
|
+
git add docs/ .claude/commands/gflow/ # include any doc-review fixes
|
|
124
|
+
# doc-review version-currency fixes often also touch ROOT docs — stage them too:
|
|
125
|
+
git add README.md PLAN.md KNOWN_ISSUES.md AGENTS.md llms.txt 2>/dev/null || true
|
|
126
|
+
git status --short # review EVERYTHING staged before committing
|
|
127
|
+
git commit -m "chore(release): v<NEW_VERSION>"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
- **`uv.lock` changes** on every version bump (the editable package version is
|
|
131
|
+
pinned in the lockfile) — it is easy to forget and must ship in this commit.
|
|
132
|
+
- The release-prep commit must NOT carry a `Co-Authored-By` trailer (see reminders).
|
|
133
|
+
|
|
134
|
+
**12. Tag the release commit.** Use `-s` for a signed annotated tag so GitHub shows **"Verified"** AND `.github/workflows/release.yml` passes the signed-tag gate (unsigned or lightweight tags are rejected by CI).
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
git tag -s v<NEW_VERSION> -m "v<NEW_VERSION>"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Signing requirements:
|
|
141
|
+
- **SSH signing (preferred):** `git config --global gpg.format ssh` + `user.signingkey` pointing at your public key.
|
|
142
|
+
- **GPG:** any registered GPG key works.
|
|
143
|
+
- Run `git config --global user.signingkey` to confirm a key is configured.
|
|
144
|
+
|
|
145
|
+
Confirm the tag actually carries a signature (this is what CI checks):
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
git cat-file -p v<NEW_VERSION> | grep -c "BEGIN SSH SIGNATURE" # expect 1 (or "BEGIN PGP SIGNATURE" for GPG)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
> **Benign local-verify error:** `git tag -v v<NEW_VERSION>` may fail with
|
|
152
|
+
> `gpg.ssh.allowedSignersFile needs to be configured`. This is a *local
|
|
153
|
+
> verification-config* gap only — the tag IS validly signed and CI still passes
|
|
154
|
+
> (CI greps for the signature header, above). To make local verify work once and
|
|
155
|
+
> for all, create an allowed-signers file (`<your-email> ssh-rsa AAAA...`) and run
|
|
156
|
+
> `git config --global gpg.ssh.allowedSignersFile <path>`. See the `release-signing`
|
|
157
|
+
> memory for the exact recipe. Do NOT treat this error as a signing failure.
|
|
158
|
+
|
|
159
|
+
**13. Push the tag first** (bypasses branch protection; triggers the CI release workflow immediately):
|
|
160
|
+
|
|
161
|
+
> **⚠ POINT OF NO RETURN — confirm with the user before this push.** Pushing the
|
|
162
|
+
> tag immediately triggers `.github/workflows/release.yml` → **PyPI publish +
|
|
163
|
+
> public GitHub Release**. A pushed release tag must NOT be force-replaced (ship a
|
|
164
|
+
> PATCH instead). Get an explicit go-ahead, then push.
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
git push origin v<NEW_VERSION>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
CI will start building the release. Watch <https://github.com/ffroliva/gflow-cli/actions>.
|
|
171
|
+
Wait for the `Release` run to report **completed / success** and confirm the GitHub
|
|
172
|
+
Release published before continuing (`gh release view v<NEW_VERSION>`).
|
|
173
|
+
|
|
174
|
+
**14. Push the release branch and open the PR.**
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
git push -u origin chore/release-v<NEW_VERSION>
|
|
178
|
+
gh pr create --base main --head chore/release-v<NEW_VERSION> \
|
|
179
|
+
--title "chore(release): v<NEW_VERSION>"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Wait for PR CI to go green (`gh pr checks <N> --watch`), then merge with a **merge
|
|
183
|
+
commit** — never squash:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
gh pr merge <N> --merge --delete-branch
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
> **NEVER `--squash` this PR.** Because the branch was cut from `develop`, the PR
|
|
190
|
+
> carries the entire batch of unreleased integration commits. A squash collapses
|
|
191
|
+
> them into one opaque commit on `main` and destroys that history. `--merge`
|
|
192
|
+
> preserves it. (The release workflow already ran from the tag push in step 13 —
|
|
193
|
+
> this PR is to bring the bump commit + integration history onto `main`.)
|
|
194
|
+
|
|
195
|
+
**15. Back-merge `main` into `develop`.**
|
|
196
|
+
|
|
197
|
+
After the release PR is merged, bring the bump commit back to `develop` so branches stay aligned:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
git checkout develop
|
|
201
|
+
git pull origin develop
|
|
202
|
+
git fetch origin main
|
|
203
|
+
git merge origin/main --no-ff -m "chore: back-merge main (v<NEW_VERSION>) into develop"
|
|
204
|
+
git push origin develop
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
If there are conflicts (rare — only if `develop` has commits that touched the same lines as the bump), resolve them, keeping `develop`'s unreleased work and `main`'s version bump.
|
|
208
|
+
|
|
209
|
+
**16. Report.**
|
|
210
|
+
|
|
211
|
+
Tell the user:
|
|
212
|
+
- Tag push triggered `.github/workflows/release.yml`.
|
|
213
|
+
- Watch <https://github.com/ffroliva/gflow-cli/actions> for the release workflow.
|
|
214
|
+
- On success: PyPI publish + GitHub Release with auto-generated notes.
|
|
215
|
+
- On failure (most common: PyPI Trusted Publishing not yet configured): point to <https://pypi.org/manage/account/publishing/>.
|
|
216
|
+
- `develop` is now synced with `main` (back-merge done in step 15).
|
|
217
|
+
- Next development cycle starts on `develop` — open `## [Unreleased]` in CHANGELOG is ready.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Critical reminders
|
|
222
|
+
|
|
223
|
+
- **ALWAYS** cut the release branch from `develop`, not `main` — `develop` carries the work.
|
|
224
|
+
- **NEVER** `--squash` the release PR into `main` — it destroys the integration history the branch carries. Use `--merge`.
|
|
225
|
+
- **NEVER** skip the `main → develop` back-merge (step 15) — skipping it guarantees conflicts at the next release.
|
|
226
|
+
- **NEVER** add `Co-Authored-By: Claude` (or any AI co-author) to the release commit.
|
|
227
|
+
- **NEVER** force-push a release tag once it's on GitHub. Ship a PATCH fix instead.
|
|
228
|
+
- **NEVER** `--no-verify` past hooks. Fix the underlying issue.
|
|
229
|
+
- **NEVER** push directly to `main` — branch protection will reject it. Always use a PR.
|
|
230
|
+
- A `git tag -v` `allowedSignersFile` error is **benign** (verify-only) — the tag is still signed and CI passes. Don't treat it as a failure.
|
|
231
|
+
- **CONFIRM with the user before the step 13 tag push** — it's the irreversible PyPI + public Release trigger.
|
|
232
|
+
- If quality gates fail at step 4, **STOP**. Surface the failures to the user.
|
|
233
|
+
- If doc-review fails at step 10, **STOP**. Fix before committing.
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## See also
|
|
238
|
+
|
|
239
|
+
- [RELEASE.md](../../../RELEASE.md) — full release protocol, prerelease policy, and checklist
|
|
240
|
+
- [README § Releases](../../../README.md#releases) — release policy and cadence
|
|
241
|
+
- [PLAN § Phase 5](../../../PLAN.md#phase-5--public-alpha-release-on-pypi) — first-release exit criteria
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Show current plan state — active plan file, goal, progress, and next unchecked task.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# `/gflow:status [feature]` — Current plan state
|
|
6
|
+
|
|
7
|
+
**Read `skills/status/SKILL.md` and follow the `status` variant protocol**, passing `$ARGUMENTS` as the optional feature slug.
|
|
8
|
+
|
|
9
|
+
> Do **not** call `Skill(skill="status")` — read the file directly.
|
|
10
|
+
|
|
11
|
+
The skill at `skills/status/SKILL.md` runs `scripts/dev/active_plan.py` and returns
|
|
12
|
+
the full output: plan file path, title, goal, progress (X/N), and next task block.
|
|
@@ -63,6 +63,9 @@ samples/*.captured.json # sandbox-recorded API exchanges may contain PII
|
|
|
63
63
|
test_assets/smoke_*/
|
|
64
64
|
test_assets/debug_*/
|
|
65
65
|
|
|
66
|
+
# Phase-2 live-spike capture outputs — NEVER commit (may contain real API payloads)
|
|
67
|
+
scripts/dev/_spike_out/
|
|
68
|
+
|
|
66
69
|
# Live Flow traffic captures — NEVER commit (contain real Bearer tokens / API keys).
|
|
67
70
|
# Diagnostic scripts MUST default-write here, NOT to samples/captured/.
|
|
68
71
|
# Sanitised reference samples (no secrets) can still live under samples/captured/.
|
|
@@ -83,3 +86,6 @@ worktrees/
|
|
|
83
86
|
|
|
84
87
|
# E2E test logs (live Flow runs — may contain account/profile names)
|
|
85
88
|
.planning/e2e-logs/
|
|
89
|
+
|
|
90
|
+
# Understand Anything (local knowledge graph)
|
|
91
|
+
.understand-anything/
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Issue #125 fix plan — `gflow video i2v` silently routes to T2V with `omni-flash`
|
|
2
|
+
|
|
3
|
+
**Branch:** `bugfix/issue-125-i2v-t2v` (worktree at `.claude/worktrees/bugfix+issue-125-i2v-t2v/`)
|
|
4
|
+
**Issue:** https://github.com/ffroliva/gflow-cli/issues/125
|
|
5
|
+
**Status:** Plan — awaiting 5-persona council review before implementation.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Root cause (confirmed at zero credit)
|
|
10
|
+
|
|
11
|
+
`omni-flash` does NOT support i2v interpolation (start+end frames). Flow's frontend silently drops the bound mediaIds at submit time and routes the request to `batchAsyncGenerateVideoText` with `image_inputs: null`. The user is charged 1 credit for a pure text-to-video generation that ignores the start/end frames entirely.
|
|
12
|
+
|
|
13
|
+
This is **NOT** the originally hypothesised selector / UI-path bug. The "Add to Prompt" click in `_upload_via_open_dialog` IS correct on both EN and pt-BR locales (probe v1). The frame slots transition correctly (`FRAME_SLOTS_STRUCT.count()` drops 2 → 1 → 0, probe v3). The submit-button selector finds the right "Criar" button (probe v3). The bug is at Flow's model-vs-request-shape compatibility check, which is invisible from the DOM.
|
|
14
|
+
|
|
15
|
+
## 2. Evidence
|
|
16
|
+
|
|
17
|
+
### Zero-credit evidence
|
|
18
|
+
|
|
19
|
+
| Probe | Sequence | Model | Captured URL | startImage | endImage |
|
|
20
|
+
|---|---|---|---|---|---|
|
|
21
|
+
| v4 prod-order | attaches → prompt → submit | (inherits Flow's last = omni-flash) | `batchAsyncGenerateVideoText` ❌ | `null` | `null` |
|
|
22
|
+
| v4 reorder | prompt → attaches → submit | omni-flash | `batchAsyncGenerateVideoText` ❌ | `null` | `null` |
|
|
23
|
+
| **v5 omni-flash + start+end** | attaches → prompt → submit | omni-flash (explicit) | `batchAsyncGenerateVideoText` ❌ | `null` | `null` |
|
|
24
|
+
| **v5 omni-flash + start-only** | Start only → prompt → submit | omni-flash (explicit) | `batchAsyncGenerateVideoText` ❌ | `null` | `null` |
|
|
25
|
+
| **v5 veo-lite + start+end** | attaches → prompt → submit | **veo-lite** | **`batchAsyncGenerateVideoStartAndEndImage` ✓** | **`4e551690...` ✓** | **`700c5522...` ✓** |
|
|
26
|
+
|
|
27
|
+
**Conclusion: omni-flash does NOT support i2v in ANY form** — neither start-only nor start+end. The strict rejection in §3 is verified, not just conservative.
|
|
28
|
+
|
|
29
|
+
Output dirs:
|
|
30
|
+
- `C:\Users\ffrol\gflow-output\i2v-intercept-prodorder-20260530-160535\evidence.json` (omni-flash, broken)
|
|
31
|
+
- `C:\Users\ffrol\gflow-output\i2v-intercept-veolite-20260530-165432\evidence.json` (veo-lite, correct)
|
|
32
|
+
|
|
33
|
+
### Human-session HAR evidence
|
|
34
|
+
|
|
35
|
+
`C:\Users\ffrol\Downloads\labs.google14.har` — manual i2v session on the same account, same UI flow as gflow. The captured generate body shows:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"videoModelKey": "veo_3_1_interpolation_lite", // ← Flow auto-promotes veo_3_1_lite → veo_3_1_interpolation_lite when start+end frames are present
|
|
40
|
+
"startImage": { "mediaId": "3c65f7ed-..." },
|
|
41
|
+
"endImage": { "mediaId": "7e70fd03-..." }
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Paid run evidence
|
|
46
|
+
|
|
47
|
+
The original gflow paid retry (`C:\Users\ffrol\gflow-output\i2v-prompt-retry-20260530-133705\_err2.log`) used `--model omni-flash` (gflow's default), produced an 8s "wake-up in bedroom" stickman video that has zero visual continuity with `01-t2i.jpg` (stickman at desk) or `02-i2i.jpg` (arms-raised triumph at sunrise). Per the structured-log `generate_captured` event, the request URL was `batchAsyncGenerateVideoText` with all-null image_inputs — pure T2V from the prompt alone.
|
|
48
|
+
|
|
49
|
+
**Retroactive impact:** every i2v paid run on `gflow v0.10.0` with the default model (or `--model omni-flash`) has been a silent T2V. The wf-004 promo "drift" was not Veo style-shift — it was a pure T2V.
|
|
50
|
+
|
|
51
|
+
## 3. Scope
|
|
52
|
+
|
|
53
|
+
### In scope (this PR) — council-revised
|
|
54
|
+
|
|
55
|
+
- Add model-vs-mode compatibility helper `VideoModel.supports_i2v_interpolation()` returning False for `OMNI_FLASH`, True for the four `VEO_3_1_*` variants. Add `I2V_DEFAULT_MODEL = VideoModel.VEO_3_1_LITE` module constant in `api/video.py` (domain).
|
|
56
|
+
- **Typed error class** `ModelModeIncompatibilityError` (new, in `gflow_cli.errors`) wired into `EXIT_CODE_MAP` with **exit code 17** (distinct from Click's exit 2 "usage error" and generic exit 1). Per CLI UX council finding: "semantic model/mode incompatibility known to the domain deserves a typed error."
|
|
57
|
+
- `gflow video i2v` CLI: drop `omni-flash` from the i2v command's `--model` Click `Choice` tuple entirely (cleanest UX per CLI UX council). The `--help` output then lists only valid models; users see the constraint at help time. Note: t2v / r2v keep `omni-flash` in their Choice.
|
|
58
|
+
- `gflow video i2v` CLI: when `--model` omitted → resolve to `I2V_DEFAULT_MODEL` (`veo-lite`). When a deserialized config still names `omni-flash` (e.g. from a stale `--config` JSON), the Click callback raises `ModelModeIncompatibilityError`.
|
|
59
|
+
- **Defense-in-depth transport guard** in `_generate_video_locked`: place **immediately after `_select_video_model` (~L1170)** and BEFORE any `_attach_frame` call (Architect + Performance both flagged this as the right placement — fails before any DOM mutation, no cleanup needed, no `page.reload()`). Guard checks `mode is Mode.I2V and (start_image is not None or end_image is not None) and not model.supports_i2v_interpolation()` → raises `ModelModeIncompatibilityError`. Catches direct `FlowApiClient` callers (gflow-cli-remotion) who bypass Click.
|
|
60
|
+
- **Structlog event** `ui_automation_video.model_mode_rejected` emitted by the transport guard before raising — fields `{model, mode, has_start_image, has_end_image, issue_ref: "#125"}`. Required for e2e assertion per CLI UX council + [[verification-ledger-5-layer]].
|
|
61
|
+
- `--model` Click `help=` text on i2v + i2v command `examples=` corrected.
|
|
62
|
+
- Unit tests for the typed error, Choice-drop, default resolution, transport guard, and structlog assertion — see §6.
|
|
63
|
+
- CHANGELOG entries under both `### Fixed` and `### Changed` (the default-model shift is a Changed behaviour worth surfacing separately).
|
|
64
|
+
- Update issue #125 with the actual root cause and link the PR.
|
|
65
|
+
- Ship two diagnostic probes (`capture_i2v_post_bind_state.py`, `capture_i2v_intercept_submit.py`). **DROP probe v1 (`capture_i2v_upload_dialog_dom.py`)** — it proved a refuted hypothesis; ship-as-doc was post-hoc justification per Devil's Advocate.
|
|
66
|
+
|
|
67
|
+
### Out of scope (deferred — with evidence-based plan)
|
|
68
|
+
|
|
69
|
+
- **r2v + omni-flash compatibility** — Devil's Advocate flagged for in-scope inclusion. Probing r2v requires extending the probe with `--mode references` (different sub-mode, different attach helper `_attach_references`, different endpoint family `batchAsyncGenerateVideoReferenceImages`). Material rewrite. **Decision: file follow-up issue with a one-line probe extension as the first task. Defer scope expansion until evidence in hand.** The plan's transport guard is structured so adding r2v rejection later is a one-line change (`mode is Mode.R2V and not model.supports_r2v(...)`).
|
|
70
|
+
- **omni-flash + start-only i2v** — RESOLVED by probe v5: also routes T2V. Already covered by the in-scope reject-omni-flash-for-any-i2v rule. No longer "unverified strictness."
|
|
71
|
+
- **Full model+mode compatibility matrix** — broader spec; separate work.
|
|
72
|
+
- **Selector-cascade hardening for `_upload_via_open_dialog`** (originally Stage A from the predict review) — no longer needed; probe v1 confirmed the selector works on pt-BR. Drop this scope. (Probe itself dropped from ship list per above.)
|
|
73
|
+
|
|
74
|
+
## 4. Files touched — council-revised
|
|
75
|
+
|
|
76
|
+
| File | Purpose | Change |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| `src/gflow_cli/api/video.py` | Domain | Add `VideoModel.supports_i2v_interpolation()` classmethod. Add `I2V_DEFAULT_MODEL = VideoModel.VEO_3_1_LITE`. Per Architect: "domain invariant, not adapter knowledge — analogous to `Aspect.wire()`." |
|
|
79
|
+
| `src/gflow_cli/errors.py` | Typed error | Add `ModelModeIncompatibilityError(GFlowError)` with `exit_code=17`. Per CLI UX council. |
|
|
80
|
+
| `src/gflow_cli/cli_video.py` | CLI surface | Drop `omni-flash` from i2v `--model` Click `Choice` (cleanest discoverability per CLI UX). Add a Click callback resolving omitted `--model` to `I2V_DEFAULT_MODEL`. Raise `ModelModeIncompatibilityError` if a deserialized config still names `omni-flash` for i2v. Update i2v `--model help=` and command examples. |
|
|
81
|
+
| `src/gflow_cli/api/transports/ui_automation_video.py` | Transport guard | In `_generate_video_locked`, **immediately after `_select_video_model` (~L1170), BEFORE `_attach_frame`**: emit `ui_automation_video.model_mode_rejected` event and raise `ModelModeIncompatibilityError` if `mode is Mode.I2V and (start_image is not None or end_image is not None) and not model.supports_i2v_interpolation()`. Per Architect + Performance: earlier placement = no DOM mutation, no cleanup needed. **No `page.reload()`** — drop the R6 mitigation entirely. |
|
|
82
|
+
| `tests/api/test_video.py` (or sibling) | Unit | `test_supports_i2v_interpolation_matrix` parametrized over all 5 VideoModel variants. `test_i2v_default_model_is_veo_lite`. |
|
|
83
|
+
| `tests/errors/test_exit_codes.py` (or sibling) | Unit | `test_model_mode_incompatibility_error_exit_code_17` + ordering-invariant. |
|
|
84
|
+
| `tests/cli/test_cli_video.py` (or sibling) | Unit | i2v --help no longer lists omni-flash; omitted --model resolves to veo-lite; explicit omni-flash via stale config raises exit 17. |
|
|
85
|
+
| `tests/api/transports/test_ui_automation_video.py` (or sibling) | Unit | `test_transport_rejects_i2v_with_omni_flash` — stubbed request DTO, assert raise + `model_mode_rejected` event captured. |
|
|
86
|
+
| `CHANGELOG.md` | Release note | New `### Fixed` entry (i2v silent T2V regression) + new `### Changed` entry (i2v default model shift to veo-lite). |
|
|
87
|
+
| `scripts/dev/capture_i2v_post_bind_state.py` | Dev tooling | NEW — slot-state regression probe. |
|
|
88
|
+
| `scripts/dev/capture_i2v_intercept_submit.py` | Dev tooling | NEW — definitive zero-credit reproducer (the smoking-gun probe). |
|
|
89
|
+
| ~~`scripts/dev/capture_i2v_upload_dialog_dom.py`~~ | ~~Dev tooling~~ | **DROPPED from ship list** — proved a refuted hypothesis; not maintaining as documentation. |
|
|
90
|
+
|
|
91
|
+
## 5. Implementation steps (in order — each a focused commit) — council-revised
|
|
92
|
+
|
|
93
|
+
1. **Add `ModelModeIncompatibilityError`** to `gflow_cli.errors` + wire into `EXIT_CODE_MAP` with `exit_code=17`. Unit test for ordering-invariant + the new mapping.
|
|
94
|
+
2. **Add `VideoModel.supports_i2v_interpolation()` + `I2V_DEFAULT_MODEL`** in `api/video.py` + unit tests.
|
|
95
|
+
3. **Drop omni-flash from i2v's `--model` Click `Choice`; add resolution callback** in `cli_video.py`. Add `ModelModeIncompatibilityError` raise for the stale-config edge case. Unit tests for both paths.
|
|
96
|
+
4. **Transport guard** at the correct placement (just after `_select_video_model`) in `_generate_video_locked` + structlog event + unit test stubbing the request DTO. Verify no `page.reload()` is added.
|
|
97
|
+
5. **Update `--model help=` text + i2v command examples** in `cli_video.py`.
|
|
98
|
+
6. **CHANGELOG**: `### Fixed` + `### Changed` entries.
|
|
99
|
+
7. **Add the two dev probes** to `scripts/dev/`: `capture_i2v_post_bind_state.py` + `capture_i2v_intercept_submit.py`. Do NOT add `capture_i2v_upload_dialog_dom.py`.
|
|
100
|
+
8. **Update issue #125** with the corrected root cause and link to the PR (in §7 verification, after merge).
|
|
101
|
+
|
|
102
|
+
## 6. Test plan — council-revised
|
|
103
|
+
|
|
104
|
+
### Unit tests
|
|
105
|
+
|
|
106
|
+
- `test_omni_flash_does_not_support_i2v_interpolation`: `VideoModel.OMNI_FLASH.supports_i2v_interpolation() is False`
|
|
107
|
+
- `test_veo_3_1_models_support_i2v_interpolation`: parametrize across the four VEO_3_1_* variants, all return True
|
|
108
|
+
- `test_i2v_default_model_constant`: `I2V_DEFAULT_MODEL is VideoModel.VEO_3_1_LITE`
|
|
109
|
+
- `test_model_mode_incompatibility_error_exit_code_is_17`: `ModelModeIncompatibilityError().exit_code == 17` and the class is registered in `EXIT_CODE_MAP`
|
|
110
|
+
- `test_exit_code_map_ordering_invariant_still_holds` after the new entry (per [[exit-code-map-ordering-invariant-test-pitfall]])
|
|
111
|
+
- `test_i2v_click_choice_excludes_omni_flash`: introspect the i2v command's `--model` Click `Choice` — `"omni-flash" not in choices`. (Compare to t2v Choice which DOES include it.)
|
|
112
|
+
- `test_i2v_cli_resolves_default_to_veo_lite`: `gflow video i2v start.jpg "p" --end-image end.jpg` (no --model) → resolved model in the request DTO is `VideoModel.VEO_3_1_LITE`
|
|
113
|
+
- `test_i2v_cli_rejects_stale_config_with_omni_flash`: a deserialized config JSON pointing at omni-flash for i2v → exits **17** (not 2) with stderr containing "#125" and "veo-lite"
|
|
114
|
+
- `test_transport_raises_on_i2v_with_omni_flash_and_end_image`: invoke `_generate_video_locked` with a stubbed request `(model=OMNI_FLASH, mode=I2V, start_image=Path, end_image=Path)` → raises `ModelModeIncompatibilityError`, structlog captures `model_mode_rejected` event with fields `{model: "omni_flash", mode: "I2V", has_start_image: True, has_end_image: True, issue_ref: "#125"}`. **No DOM mutation must have occurred** — assert no `_attach_frame` call fired (via mock).
|
|
115
|
+
- `test_transport_raises_on_i2v_with_omni_flash_and_start_only`: same shape but `end_image=None`, `start_image=Path` — still raises (omni-flash rejected for any i2v ref, per probe evidence).
|
|
116
|
+
- `test_transport_does_NOT_raise_on_t2v_with_omni_flash`: pure t2v + omni-flash is a valid combination — guard must NOT fire.
|
|
117
|
+
|
|
118
|
+
### Integration tests
|
|
119
|
+
|
|
120
|
+
- BDD scenario: "user runs i2v with default model" → command resolves to veo-lite, no Flow interaction. Assert `structlog` shows `model_mode_rejected` is NOT emitted.
|
|
121
|
+
- BDD scenario: "in-process API caller (e.g. flow_workflow.py shape) passes `model=OMNI_FLASH, mode=I2V, start_image=Path` to `FlowApiClient.generate_video`" → raises `ModelModeIncompatibilityError`, exit code 17. **This is the safety net for gflow-cli-remotion-style consumers.**
|
|
122
|
+
- Audit existing i2v integration tests: any fixture using omni-flash for i2v must be updated to a Veo 3.1 model.
|
|
123
|
+
|
|
124
|
+
### Live e2e (1 paid credit)
|
|
125
|
+
|
|
126
|
+
- Re-run probe v5 (`capture_i2v_intercept_submit.py --model veo-lite ...`) zero-credit sanity check — captured URL must still be `StartAndEndImage` with bound mediaIds.
|
|
127
|
+
- Then a live `gflow video i2v 01-t2i.jpg "<tightened stickman motion prompt>" --end-image 02-i2i.jpg --model veo-lite --aspect 9:16 --profile promo-denon82` → expect:
|
|
128
|
+
- structured log `ui_automation_video.generate_captured` event with `url=batchAsyncGenerateVideoStartAndEndImage` and `image_inputs.startImage` + `image_inputs.endImage` non-null
|
|
129
|
+
- **assert structured log does NOT contain `ui_automation_video.model_mode_rejected`** (positive verification that the new guard didn't false-fire on a valid combination)
|
|
130
|
+
- output mp4 visually: 2D ink line-art stickman starting at desk (matches 01-t2i.jpg), interpolating to arms-raised at sunrise (matches 02-i2i.jpg)
|
|
131
|
+
- 5-layer verification ledger per memory [[verification-ledger-5-layer]]: file count, magic bytes (mp4 signature), Pillow dims (720×1280), structlog invariants (above), user gallery confirmation.
|
|
132
|
+
|
|
133
|
+
## 7. Verification ladder (definition of done) — council-revised
|
|
134
|
+
|
|
135
|
+
- [ ] `ruff format --check` + `ruff check` clean on `src/gflow_cli/{cli_video,errors,api/video,api/transports/ui_automation_video}.py` and the two dev probe scripts shipping.
|
|
136
|
+
- [ ] `pyright` clean on the same scoped paths.
|
|
137
|
+
- [ ] All new unit tests pass (see §6).
|
|
138
|
+
- [ ] Scoped pytest of `tests/cli/` + `tests/api/` + `tests/api/transports/` + `tests/errors/` passes (full sweep deferred to CI per [[full-test-suite-ooms]]).
|
|
139
|
+
- [ ] BDD/integration tests pass.
|
|
140
|
+
- [ ] **Exit-code-map ordering-invariant test passes** (per [[exit-code-map-ordering-invariant-test-pitfall]]) — adding code 17 must not invert any prior subclass-relation invariant.
|
|
141
|
+
- [ ] Probe v5 re-run with `--model veo-lite` still produces `StartAndEndImage` URL with bound mediaIds (zero credit).
|
|
142
|
+
- [ ] Probe v5 re-run with `--model omni-flash --start-only` still produces T2V (zero credit — proves the rejection is still warranted).
|
|
143
|
+
- [ ] 1 paid live e2e i2v run completes; structured log shows `generate_captured.url=batchAsyncGenerateVideoStartAndEndImage` with non-null mediaIds AND `model_mode_rejected` event is NOT emitted.
|
|
144
|
+
- [ ] User watches the output mp4 and verbally confirms it's a 2D ink line-art stickman desk → sunrise scene matching the refs.
|
|
145
|
+
- [ ] Issue #125 comment thread updated with the actual root cause + closed by PR merge.
|
|
146
|
+
- [ ] CHANGELOG entries present under `[Unreleased]` — both `### Fixed` and `### Changed`.
|
|
147
|
+
|
|
148
|
+
## 8. Risks + mitigations
|
|
149
|
+
|
|
150
|
+
| Risk | Severity | Mitigation |
|
|
151
|
+
|---|---|---|
|
|
152
|
+
| R1: Changing default model silently surprises users who already had a working incantation | LOW — prior incantation was broken (T2V output); making it work correctly is a strict improvement | None needed beyond clear CHANGELOG note |
|
|
153
|
+
| R2: veo-lite has different cost/quality than omni-flash | LOW — both are tier-one lite models; veo-3.1-lite cost is documented in Flow's UI per `MEDIA_GENERATION_PAYGATE_TIER: PAYGATE_TIER_ONE` | Document in --model help text |
|
|
154
|
+
| R3: omni-flash + start-only i2v might actually work (unverified) | MEDIUM — if it does work, our strict rejection blocks a valid combination | Conservative reject in this PR; reverse with probe evidence in a follow-up if proven |
|
|
155
|
+
| R4: r2v + omni-flash has the same silent-drop pathology | MEDIUM — separate UI surface, separate ticket needed | Out of scope; file follow-up issue with link from #125 |
|
|
156
|
+
| R5: Hidden in-process API callers (scripts using `FlowApiClient` directly like `gflow-cli-remotion/flow_workflow.py`) bypass the CLI validation | MEDIUM | The transport guard in `_generate_video_locked` is the safety net for these callers |
|
|
157
|
+
| ~~R6: pre-submit guard raises but the page is left in a dirty state for the pool~~ | ~~LOW~~ | **DROPPED per Performance council review.** Guard now placed at L1170 (immediately after `_select_video_model`, BEFORE any `_attach_frame`) — fires before any DOM-state mutation, no Page cleanup needed, no `page.reload()`. Architect concurred ("earlier-fail is cleaner than dirty-state cleanup"). |
|
|
158
|
+
|
|
159
|
+
## 9. Rollback
|
|
160
|
+
|
|
161
|
+
- Revert the PR as a single commit-range. No DB migrations, no settings changes, no state mutations.
|
|
162
|
+
- The transport guard fails-closed: if a user with cached venv hits the guard on a stale config, they get a clear error pointing at #125 with remediation. No silent regression.
|
|
163
|
+
|
|
164
|
+
## 10. CHANGELOG entries — council-revised (two sections)
|
|
165
|
+
|
|
166
|
+
```markdown
|
|
167
|
+
### Fixed
|
|
168
|
+
|
|
169
|
+
- `gflow video i2v` silently routed every call to the T2V endpoint with
|
|
170
|
+
`image_inputs: null` when the model was `omni-flash` (Flow's last-used
|
|
171
|
+
default in most sessions). Flow's frontend rejects omni-flash + frame
|
|
172
|
+
refs and falls back to text-only generation, but the rejection is
|
|
173
|
+
invisible to the client — every i2v paid run on v0.10.0 burned a
|
|
174
|
+
credit for a pure text-to-video generation that ignored the supplied
|
|
175
|
+
start/end frames. Issue #125. Fix: omni-flash dropped from the i2v
|
|
176
|
+
`--model` Click `Choice` entirely; a defense-in-depth transport guard
|
|
177
|
+
in `_generate_video_locked` raises `ModelModeIncompatibilityError`
|
|
178
|
+
(exit code 17) for direct `FlowApiClient` callers that bypass the CLI.
|
|
179
|
+
|
|
180
|
+
### Changed
|
|
181
|
+
|
|
182
|
+
- `gflow video i2v` default model is now `veo-lite` (was: inherit
|
|
183
|
+
Flow's last-used, which was typically `omni-flash` — see Fixed). The
|
|
184
|
+
veo-3.1 family is the only model line that supports i2v
|
|
185
|
+
interpolation; omni-flash is now correctly rejected for any i2v
|
|
186
|
+
invocation (start-only or start+end). Explicit `--model omni-flash`
|
|
187
|
+
for `gflow video t2v` and `gflow video r2v` remains valid.
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## 11. Migration / backward compat
|
|
191
|
+
|
|
192
|
+
- No breaking config or env-var changes.
|
|
193
|
+
- v0.10.0 users running `gflow video i2v ... --end-image ...` without explicit `--model` previously got silent T2V output; they now get correct interpolation (silent improvement, no surprise).
|
|
194
|
+
- v0.10.0 users running `gflow video i2v ... --end-image ... --model omni-flash` previously got silent T2V; they now get a clear error with `gflow video i2v ... --end-image ... --model veo-lite` as the remediation.
|
|
195
|
+
- BREAKING for: nobody. The prior behavior was a silent bug.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Appendix: probe scripts
|
|
200
|
+
|
|
201
|
+
All zero-credit. Only two ship in this PR per Devil's Advocate review (probe v1 dropped — proved a refuted hypothesis, no future-locale-regression value).
|
|
202
|
+
|
|
203
|
+
| Probe | What it proved | Ships? |
|
|
204
|
+
|---|---|---|
|
|
205
|
+
| `capture_i2v_upload_dialog_dom.py` | "Incluir no comando" pt-BR button matches the production `add_btn` selector — selector cascade is correct (REFUTED original hypothesis). | **NO** — proved a refuted hypothesis; not maintaining as documentation. |
|
|
206
|
+
| `capture_i2v_post_bind_state.py` | `FRAME_SLOTS_STRUCT.count()` transitions 2 → 1 → 0 after binds; submit button is unambiguous (single arrow_forward "Criar" button); slots stay bound after prompt typing. | **YES** — useful future probe for slot-state regressions. |
|
|
207
|
+
| `capture_i2v_intercept_submit.py` | Intercepts the submit XHR via `page.route(..., abort)` and inspects the request body. omni-flash → T2V with null images (both start+end and start-only); veo-lite → StartAndEndImage with populated mediaIds. **This is the definitive reproducer.** | **YES** — definitive regression probe for future model/mode work. |
|
|
@@ -8,7 +8,8 @@ Supported tools that auto-discover this file: Cursor, Codex, Aider, Jules, Devin
|
|
|
8
8
|
|
|
9
9
|
- Unofficial Python CLI for [Google Flow](https://labs.google/fx/tools/flow) — drives Veo (image-to-video, text-to-video) and Imagen (text-to-image) generations from the terminal by reverse-engineering Flow's private REST API at `aisandbox-pa.googleapis.com`.
|
|
10
10
|
- Python 3.11+ · `uv`-managed · `hatchling` builds · Playwright Chromium transport · `pyright` strict · `ruff` · `pytest`.
|
|
11
|
-
- Single-package modular monolith. Top-level modules under `src/gflow_cli/`: `api/`, `auth/`, `browser_manager.py`, `cli.py`, `_cli_helpers.py`, `cli_data.py`, `cli_image.py`, `cli_run.py`, `cli_video.py`, `config.py`, `data/`, `errors.py`, `exceptions.py`, `image_batch.py`, `manifest.py`, `observability.py`, `paths.py`, `profile_store.py`.
|
|
11
|
+
- Single-package modular monolith. Top-level modules under `src/gflow_cli/`: `api/`, `auth/`, `browser_manager.py`, `cli.py`, `_cli_helpers.py`, `cli_character.py`, `cli_data.py`, `cli_image.py`, `cli_models.py`, `cli_run.py`, `cli_scene.py`, `cli_video.py`, `config.py`, `data/`, `errors.py`, `exceptions.py`, `image_batch.py`, `manifest.py`, `observability.py`, `paths.py`, `profile_store.py`.
|
|
12
|
+
- Command surface: `gflow auth`, `gflow image` (t2i/i2i/upload), `gflow video` (t2v/i2v/r2v/batch/chain), `gflow character` (create/list/show/voices — reusable project-scoped Flow Character entities), `gflow scene` (create/show — Add Clip / Scenes, with `create --output` for credit-free server-side extended video), and `gflow data` (catalog queries).
|
|
12
13
|
- Requires a Google AI Ultra or Pro subscription with Flow access. All generations bill against the user's own Google account.
|
|
13
14
|
|
|
14
15
|
## Headed-browser dependency (architectural reality)
|
|
@@ -28,7 +29,7 @@ If you can help unblock a pure HTTP transport (especially for video generation,
|
|
|
28
29
|
- Copy `.env.template` to `.env.local`; never commit `.env.local`. It documents every env var.
|
|
29
30
|
- Output goes to `./tmp/` for scripts/tests or `$GFLOW_CLI_OUTPUT_DIR` for CLI outputs (defaults to `./out/`).
|
|
30
31
|
- One-time auth: `gflow auth login --browser chrome`. The `--browser chrome` flag is mandatory; the CLI fails fast on other strategies.
|
|
31
|
-
- Use `/gflow:
|
|
32
|
+
- Use `/gflow:status` to see the current task before starting work; `/gflow:known-issues` before touching auth or reCAPTCHA code paths.
|
|
32
33
|
|
|
33
34
|
## Testing instructions — The Impeccable Routine
|
|
34
35
|
|
|
@@ -55,7 +56,7 @@ Or invoke the wrapper: `/gflow:check`.
|
|
|
55
56
|
|
|
56
57
|
- Type hints everywhere; `pyright` strict on `src/gflow_cli`.
|
|
57
58
|
- Structured logging only (`structlog`) — **never** raw `print()` or `import logging` in `src/`.
|
|
58
|
-
- Errors as RFC 9457 Problem Details with stable per-class exit codes (3–
|
|
59
|
+
- Errors as RFC 9457 Problem Details with stable per-class exit codes (3–21, e.g. 16 is the `DataStoreError` family, 19 `SceneConcatError`, 20 `FrameExtractionError`, 21 `ChainPartialError`). See `src/gflow_cli/errors.py::EXIT_CODE_MAP` for the complete mapping.
|
|
59
60
|
- 100-char line length, `ruff` configured. Imports sorted by `ruff` (isort rules).
|
|
60
61
|
|
|
61
62
|
## PR instructions
|
|
@@ -66,13 +67,30 @@ Or invoke the wrapper: `/gflow:check`.
|
|
|
66
67
|
- Run `/gflow:check` (or the Impeccable Routine) before every commit.
|
|
67
68
|
- All releases require a signed annotated tag (`git tag -s vX.Y.Z`); CI rejects unsigned tags.
|
|
68
69
|
|
|
70
|
+
## Skills reference (cross-tool)
|
|
71
|
+
|
|
72
|
+
The `skills/` directory ships installable agent skill docs in plain Markdown with YAML frontmatter. Any agent can consume them directly:
|
|
73
|
+
|
|
74
|
+
| Skill | Path | When to load |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| `gflow-cli` | [`skills/gflow-cli/SKILL.md`](skills/gflow-cli/SKILL.md) | User wants to run any `gflow` command — auth, T2V, I2V, T2I, I2I, batch |
|
|
77
|
+
| `predict` | [`skills/predict/SKILL.md`](skills/predict/SKILL.md) | Pre-implementation adversarial analysis before any high-stakes change |
|
|
78
|
+
| `scenario` | [`skills/scenario/SKILL.md`](skills/scenario/SKILL.md) | Edge-case explorer after a predict GO/CAUTION |
|
|
79
|
+
| `pr-council-review` | [`skills/pr-council-review/SKILL.md`](skills/pr-council-review/SKILL.md) | Multi-dimensional PR council review |
|
|
80
|
+
|
|
81
|
+
**Cursor / Aider / Codex / Gemini CLI:** paste or include the relevant `SKILL.md` in your system context.
|
|
82
|
+
**Claude Code:** symlink `skills/gflow-cli` to `~/.claude/skills/gflow-cli` to register the skill; the `/gflow:` slash commands (in `.claude/commands/gflow/`) are auto-discovered from the project directory.
|
|
83
|
+
**Custom agents:** fetch `skills/gflow-cli/SKILL.md` into your knowledge base before answering gflow questions.
|
|
84
|
+
|
|
85
|
+
The SkillOpt harness at `scripts/dev/skillopt/` measures how accurately each skill guides an agent, and supports multiple providers (Anthropic, OpenAI-compat, Gemini, local models). See [`scripts/dev/skillopt/README.md`](scripts/dev/skillopt/README.md).
|
|
86
|
+
|
|
69
87
|
## Where to look next
|
|
70
88
|
|
|
71
89
|
- **Architecture & target shape** → [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
|
72
90
|
- **Mandates & routing rules** → [docs/AGENT_GUIDE.md](docs/AGENT_GUIDE.md)
|
|
73
91
|
- **Full docs index** → [docs/INDEX.md](docs/INDEX.md)
|
|
74
92
|
- **Known issues** (read before touching auth / reCAPTCHA) → [KNOWN_ISSUES.md](KNOWN_ISSUES.md)
|
|
75
|
-
- **
|
|
93
|
+
- **Current task** → `/gflow:status` · **Create a feature plan** → `/gflow:plan <feature>` · **Full roadmap** → [PLAN.md](PLAN.md)
|
|
76
94
|
- **Release protocol** → [RELEASE.md](RELEASE.md)
|
|
77
95
|
|
|
78
96
|
## Claude Code-specific notes
|