gflow-cli 0.6.0a4__tar.gz → 0.7.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.6.0a4 → gflow_cli-0.7.0}/.claude/README.md +8 -3
- gflow_cli-0.7.0/.claude/commands/gflow/changelog.md +21 -0
- gflow_cli-0.7.0/.claude/commands/gflow/check.md +48 -0
- gflow_cli-0.7.0/.claude/commands/gflow/known-issues.md +20 -0
- gflow_cli-0.7.0/.claude/commands/gflow/plan.md +39 -0
- gflow_cli-0.7.0/.claude/commands/gflow/release.md +118 -0
- gflow_cli-0.7.0/.github/CODEOWNERS +23 -0
- gflow_cli-0.7.0/.github/PULL_REQUEST_TEMPLATE.md +20 -0
- gflow_cli-0.7.0/.github/copilot-instructions.md +24 -0
- gflow_cli-0.7.0/.github/dependabot.yml +34 -0
- gflow_cli-0.7.0/.github/workflows/ci.yml +104 -0
- gflow_cli-0.7.0/.github/workflows/external-pr-triage.yml +126 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/.github/workflows/release.yml +18 -3
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/.gitignore +13 -0
- gflow_cli-0.7.0/.gitleaks.toml +33 -0
- gflow_cli-0.7.0/.pre-commit-config.yaml +38 -0
- gflow_cli-0.7.0/.secrets.baseline +152 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/CHANGELOG.md +151 -1
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/CLAUDE.md +30 -18
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/CONTRIBUTING.md +47 -14
- gflow_cli-0.7.0/KNOWN_ISSUES.md +326 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/PKG-INFO +25 -44
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/PLAN.md +215 -1
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/README.md +24 -43
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/RELEASE.md +2 -2
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/ARCHITECTURE.md +5 -0
- gflow_cli-0.7.0/docs/DEBUGGING.md +183 -0
- gflow_cli-0.7.0/docs/DEVELOPMENT.md +125 -0
- gflow_cli-0.7.0/docs/GITHUB.md +139 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/INDEX.md +29 -0
- gflow_cli-0.7.0/docs/LIVE_VERIFICATION_v0.7.0.md +110 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/SECURITY.md +37 -1
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/USAGE.md +64 -10
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/USER_GUIDE.md +248 -0
- gflow_cli-0.7.0/docs/superpowers/2026-05-17-issue-15-handover.md +59 -0
- gflow_cli-0.7.0/docs/superpowers/plans/2026-05-17-e2e-test-coverage.md +463 -0
- gflow_cli-0.7.0/docs/superpowers/plans/2026-05-17-issue-15-auth-verification-fix.md +1449 -0
- gflow_cli-0.7.0/docs/superpowers/plans/2026-05-17-issue-15-i2v-bearer-auth.md +811 -0
- gflow_cli-0.7.0/docs/superpowers/plans/2026-05-17-issue-15-orchestration.md +118 -0
- gflow_cli-0.7.0/docs/superpowers/plans/2026-05-18-video-phase0-submit-spike.md +697 -0
- gflow_cli-0.7.0/docs/superpowers/plans/2026-05-19-video-phase-a-execution-state.md +64 -0
- gflow_cli-0.7.0/docs/superpowers/plans/2026-05-19-video-phase-a-orchestration.md +164 -0
- gflow_cli-0.7.0/docs/superpowers/plans/2026-05-19-video-phase-a-t2v.md +2083 -0
- gflow_cli-0.7.0/docs/superpowers/specs/2026-05-17-e2e-test-coverage-design.md +190 -0
- gflow_cli-0.7.0/docs/superpowers/specs/2026-05-17-i2v-uploadimage-401-bearer-auth-design.md +330 -0
- gflow_cli-0.7.0/docs/superpowers/specs/2026-05-17-issue-15-auth-verification-fix-design.md +485 -0
- gflow_cli-0.7.0/docs/superpowers/specs/2026-05-17-issue-15-root-cause-findings.md +87 -0
- gflow_cli-0.7.0/docs/superpowers/specs/2026-05-18-ui-automation-video-generation-design.md +739 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/pyproject.toml +2 -1
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/samples/captured/02_batchAsyncGenerateVideoText.json +3 -3
- gflow_cli-0.7.0/samples/captured/08_batchAsyncGenerateVideoStartAndEndImage.json +144 -0
- gflow_cli-0.7.0/samples/captured/09_batchAsyncGenerateVideoReferenceImages.json +136 -0
- gflow_cli-0.7.0/samples/captured/10_batchCheckAsyncVideoGenerationStatus_successful.json +90 -0
- gflow_cli-0.7.0/samples/captured/11_batchCheckAsyncVideoGenerationStatus_failed.json +97 -0
- gflow_cli-0.7.0/scripts/ci/check_repo_hygiene.py +141 -0
- gflow_cli-0.7.0/scripts/debug_editor.py +69 -0
- gflow_cli-0.7.0/scripts/debug_gen_settings.py +83 -0
- gflow_cli-0.7.0/scripts/debug_settings.py +69 -0
- gflow_cli-0.7.0/scripts/dev/active_plan.py +188 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/scripts/diag_capture_flow_traffic.py +1 -1
- gflow_cli-0.7.0/scripts/smoke_video_editor.py +874 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/scripts/smoke_worker_style.py +188 -38
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/scripts/verify_chrome_auth_viability.py +9 -9
- gflow_cli-0.7.0/sonar-project.properties +35 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/__init__.py +1 -1
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/__init__.py +1 -3
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/_retry.py +2 -1
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/client.py +178 -119
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/dto.py +0 -67
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/image.py +4 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/recaptcha.py +1 -1
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/base.py +2 -2
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/experimental/bearer.py +7 -3
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/experimental/evaluate_fetch.py +7 -1
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/experimental/sapisidhash.py +6 -1
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/ui_automation.py +499 -60
- gflow_cli-0.7.0/src/gflow_cli/api/transports/ui_automation_video.py +498 -0
- gflow_cli-0.7.0/src/gflow_cli/api/video.py +156 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/auth/__init__.py +2 -2
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/auth/internal_chromium.py +56 -27
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/auth/real_chrome.py +72 -44
- gflow_cli-0.7.0/src/gflow_cli/auth/verification.py +228 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/browser_manager.py +93 -111
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/cli_image.py +46 -30
- gflow_cli-0.7.0/src/gflow_cli/cli_video.py +95 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/config.py +7 -6
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/errors.py +58 -4
- gflow_cli-0.7.0/src/gflow_cli/exceptions.py +25 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/image_batch.py +0 -1
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/manifest.py +18 -17
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tasks/lessons.md +34 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_client.py +90 -4
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_client_image.py +116 -65
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_concurrency.py +1 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_dto.py +1 -38
- gflow_cli-0.7.0/tests/api/test_video.py +213 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/test_evaluate_fetch.py +2 -2
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/test_ui_automation.py +291 -40
- gflow_cli-0.7.0/tests/api/transports/test_ui_automation_video.py +392 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/auth/strategies/test_strategies.py +150 -56
- gflow_cli-0.7.0/tests/auth/test_verification.py +301 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/cli/test_error_handling.py +17 -1
- gflow_cli-0.7.0/tests/e2e/conftest.py +67 -0
- gflow_cli-0.7.0/tests/e2e/test_auth_verification_e2e.py +65 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/e2e/test_transports_e2e.py +73 -1
- gflow_cli-0.7.0/tests/e2e/test_video_t2v_e2e.py +139 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/conftest.py +0 -2
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/test_step_collision_guard.py +2 -4
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_browser_manager.py +9 -0
- gflow_cli-0.7.0/tests/test_cli_video.py +44 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_config.py +6 -5
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_errors.py +28 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_smoke.py +2 -1
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/uv.lock +184 -1
- gflow_cli-0.6.0a4/.claude/commands/release.md +0 -97
- gflow_cli-0.6.0a4/.github/workflows/ci.yml +0 -42
- gflow_cli-0.6.0a4/KNOWN_ISSUES.md +0 -184
- gflow_cli-0.6.0a4/scripts/smoke_e2e.py +0 -78
- gflow_cli-0.6.0a4/src/gflow_cli/api/video.py +0 -112
- gflow_cli-0.6.0a4/src/gflow_cli/cli_video.py +0 -341
- gflow_cli-0.6.0a4/tests/api/test_client_generate_video.py +0 -93
- gflow_cli-0.6.0a4/tests/api/test_video.py +0 -83
- gflow_cli-0.6.0a4/tests/features/test_video_steps.py +0 -253
- gflow_cli-0.6.0a4/tests/features/video.feature +0 -27
- gflow_cli-0.6.0a4/tests/test_cli_video.py +0 -220
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/.env.template +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/.gitattributes +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/.planning/todos/pending/2026-05-11-add-project-logo-and-docs-site-promotion-plan.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/CONFIGURATION.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/DISCLAIMER.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/LICENSE +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/AUTHENTICATION.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/CONFIGURATION.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/assets/example-run.gif +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-09-image-mvp-orchestration.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-09-image-mvp.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-09-video-mvp-orchestration.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-09-video-mvp.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-10-phase-4-hardening-orchestration.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-10-phase-4-hardening.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/2026-05-14-shell-multi-prompt-orchestration.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_FINAL_ARCH.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_FINAL_SEC_UX.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_CODE.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_GEMINI.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/COUNCIL_REVIEW_SECURITY.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/IMPLEMENTATION_REVIEW_PYTHON.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/IMPLEMENTATION_REVIEW_SECURITY.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_CODE.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_FOLLOWUP.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_PLANNER.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_SECURITY.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN_REVIEW_SECURITY_FOLLOWUP.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/COUNCIL_FINAL_SEC_UX_VERIFIED.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/COUNCIL_REVIEW_PLAN_SECURITY.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/COUNCIL_REVIEW_SPEC_SECURITY.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/PLAN.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/orchestration.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/specs/2026-05-10-phase-4-hardening-design.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/specs/2026-05-14-shell-multi-prompt-design.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/specs/2026-05-15-auth-login-real-chrome-design.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/verifications/2026-05-11-phase-4-stage-g.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/examples/README.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/examples/batch_from_config.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/examples/multi_prompt_t2i.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/examples/sample_config.json +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/examples/sample_prompts.txt +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/examples/single_image_t2i.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/samples/README.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/samples/captured/01_upload_image.json +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/samples/captured/04_archive_workflow.json +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/samples/captured/05_createProject.json +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/samples/captured/06_batchGenerateImages.json +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/samples/captured/07_batchGenerateImages_seeded.json +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/scripts/diag_recaptcha_mint.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/scripts/record_demo.ps1 +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/scripts/smoke_image.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/scripts/smoke_real_chrome_image.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/skills/README.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/skills/gflow-cli/SKILL.md +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/__main__.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/_cli_helpers.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/routes.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/__init__.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/_common.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/_fingerprint.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/experimental/__init__.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/auth/base.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/auth/factory.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/auth/strategies.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/cli.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/cli_run.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/observability.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/paths.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/profile_store.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/__init__.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/__init__.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_image.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_image_dto.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_recaptcha.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_retry.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_routes.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/__init__.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/test_base.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/test_bearer.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/test_common.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/test_factory.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/test_fingerprint.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/test_sapisidhash.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/auth/strategies/test_factory.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/cli/__init__.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/cli/test_cli_image.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/cli/test_cli_run.py +1 -1
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/cli/test_helpers.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/cli/test_t2i_multi_prompt.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/conftest.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/e2e/__init__.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/__init__.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/auth.feature +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/auth_login.feature +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/image.feature +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/test_auth_login_steps.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/test_auth_steps.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/test_image_steps.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/smoke/__init__.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/smoke/test_real_flow.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_auth.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_manifest.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_observability.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_paths.py +0 -0
- {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_profile_store.py +0 -0
|
@@ -10,7 +10,12 @@ This directory holds **internal maintainer workflows** that are bundled with the
|
|
|
10
10
|
.claude/
|
|
11
11
|
├── README.md ← this file
|
|
12
12
|
└── commands/ ← repo-local slash commands
|
|
13
|
-
└──
|
|
13
|
+
└── gflow/ ← `/gflow:*` namespace (avoids collision with built-ins)
|
|
14
|
+
├── check.md ← `/gflow:check` — hygiene + ruff + pyright + pytest
|
|
15
|
+
├── plan.md ← `/gflow:plan` — show active phase / superpowers plan
|
|
16
|
+
├── known-issues.md← `/gflow:known-issues` — open/mitigated items
|
|
17
|
+
├── changelog.md ← `/gflow:changelog` — [Unreleased] + last tagged
|
|
18
|
+
└── release.md ← `/gflow:release` — full release flow (signed tags)
|
|
14
19
|
```
|
|
15
20
|
|
|
16
21
|
Optional additions when needed:
|
|
@@ -25,9 +30,9 @@ Optional additions when needed:
|
|
|
25
30
|
|
|
26
31
|
## Adding a slash command
|
|
27
32
|
|
|
28
|
-
Drop a Markdown file into `commands
|
|
33
|
+
Drop a Markdown file into `commands/gflow/` to add a `/gflow:<name>` command. Filename (without `.md`) becomes the command name. The first paragraph is the description Claude shows in `/help`. The rest is the prompt the agent executes. **Use the `gflow/` subdirectory** so commands stay namespaced and don't collide with Claude Code built-ins or user-global commands.
|
|
29
34
|
|
|
30
|
-
Example: `commands/foo.md` → invoked as `/foo`.
|
|
35
|
+
Example: `commands/gflow/foo.md` → invoked as `/gflow:foo`.
|
|
31
36
|
|
|
32
37
|
## Adding an internal skill
|
|
33
38
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Show unreleased changes and last tagged version — insight into recent work.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# `/gflow:changelog` — Recent changes
|
|
6
|
+
|
|
7
|
+
Read CHANGELOG.md and surface what's queued and what recently shipped.
|
|
8
|
+
|
|
9
|
+
## Steps
|
|
10
|
+
|
|
11
|
+
1. Read [CHANGELOG.md](../../../CHANGELOG.md)
|
|
12
|
+
2. Return:
|
|
13
|
+
- All entries under `## [Unreleased]` (empty = nothing queued yet)
|
|
14
|
+
- The most recent versioned section (last tagged release) for comparison
|
|
15
|
+
3. One-line summary: "X features, Y fixes queued since vZ."
|
|
16
|
+
|
|
17
|
+
## When to call
|
|
18
|
+
|
|
19
|
+
- Before cutting a release (called automatically by `/gflow:release` as its first step)
|
|
20
|
+
- When you need a quick picture of recent work without opening the file
|
|
21
|
+
- When writing a commit message and unsure if a change is user-visible enough to log
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Auto-fix lint and formatting, then report types and tests. Run before every commit.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# `/gflow:check` — Quality gates
|
|
6
|
+
|
|
7
|
+
Run in order. Stop and report if a step fails after the fix pass.
|
|
8
|
+
|
|
9
|
+
## Steps
|
|
10
|
+
|
|
11
|
+
**1. Repo hygiene** (read-only — checks tmp/ output rule, secret files, etc.)
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
PYTHONUTF8=1 uv run python scripts/ci/check_repo_hygiene.py
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**2. Auto-fix lint and formatting** (rewrites files in place)
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
uv run ruff check --fix src tests
|
|
21
|
+
uv run ruff format src tests
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Report which files were modified. Do NOT stage or commit — leave the diff for review.
|
|
25
|
+
|
|
26
|
+
**3. Type check** (report only — cannot auto-fix)
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
uv run pyright src
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**4. Tests + coverage** (report only)
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
uv run pytest -q --cov=gflow_cli --cov-fail-under=80
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Output
|
|
39
|
+
|
|
40
|
+
- List files changed by the fix pass (empty = nothing needed fixing)
|
|
41
|
+
- All pyright errors with `file:line` references
|
|
42
|
+
- Pytest summary line and coverage percentage
|
|
43
|
+
- Final verdict: all gates pass / which gates failed
|
|
44
|
+
|
|
45
|
+
## Notes
|
|
46
|
+
|
|
47
|
+
Ruff fix and format may rewrite multiple files. Always `git diff` before staging.
|
|
48
|
+
Pyright errors and test failures require manual intervention — do not attempt silent workarounds.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Surface open known issues. Call before touching auth, reCAPTCHA, or anything previously flagged.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# `/gflow:known-issues` — Open issues
|
|
6
|
+
|
|
7
|
+
Read KNOWN_ISSUES.md and return items that are still open or mitigated (not resolved).
|
|
8
|
+
|
|
9
|
+
## Steps
|
|
10
|
+
|
|
11
|
+
1. Read [KNOWN_ISSUES.md](../../../KNOWN_ISSUES.md)
|
|
12
|
+
2. Return only items with status **open** or **mitigated**
|
|
13
|
+
3. Flag any that are relevant to the current task context
|
|
14
|
+
|
|
15
|
+
## When to call
|
|
16
|
+
|
|
17
|
+
- Before touching `src/gflow_cli/auth.py`
|
|
18
|
+
- Before touching `src/gflow_cli/api/recaptcha.py`
|
|
19
|
+
- Before any work the user flags as "this felt flaky before"
|
|
20
|
+
- When a test or behaviour feels unexpectedly broken
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Show the active plan — next task if a superpowers plan is running, current phase otherwise.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# `/gflow:plan` — Active plan
|
|
6
|
+
|
|
7
|
+
## Steps
|
|
8
|
+
|
|
9
|
+
**1. Check conversation context.**
|
|
10
|
+
|
|
11
|
+
Has the user mentioned a specific feature or invoked the write-plan skill in this session?
|
|
12
|
+
If yes, note the feature name (e.g. `shell-multi-prompt`, `image-mvp`, `phase-4-hardening`).
|
|
13
|
+
|
|
14
|
+
**2. Run the discovery script.**
|
|
15
|
+
|
|
16
|
+
With a feature name identified in step 1:
|
|
17
|
+
```bash
|
|
18
|
+
uv run python scripts/dev/active_plan.py --feature <feature-name>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Without a feature name (uses most-recent superpowers plan, falls back to PLAN.md):
|
|
22
|
+
```bash
|
|
23
|
+
uv run python scripts/dev/active_plan.py
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**3. Return the output verbatim.**
|
|
27
|
+
|
|
28
|
+
The script already filters to the relevant block. Do not read additional files.
|
|
29
|
+
|
|
30
|
+
## What the script returns
|
|
31
|
+
|
|
32
|
+
- **Superpowers plan active:** file path, title, goal, progress (X/N steps), and the next unchecked task block
|
|
33
|
+
- **No superpowers plan:** the first incomplete phase from `PLAN.md` (scope, sequence, definition of done)
|
|
34
|
+
|
|
35
|
+
## When to call
|
|
36
|
+
|
|
37
|
+
- When starting a task and unsure what's in scope
|
|
38
|
+
- When the user asks "what are we working on?" or "what's next?"
|
|
39
|
+
- Before adding a feature, to check it belongs to the current scope
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Cut a new gflow-cli release — bump version, update CHANGELOG, tag, push.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# `/gflow:release` — Cut a new release
|
|
6
|
+
|
|
7
|
+
Follow this sequence verbatim. Every step matters.
|
|
8
|
+
|
|
9
|
+
## Inputs
|
|
10
|
+
|
|
11
|
+
Ask the user (if not already provided):
|
|
12
|
+
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).
|
|
13
|
+
2. **Pre-release?** — prerelease versions should stay marked as GitHub prereleases. Only the user can say when a release line is ready for the stable tag.
|
|
14
|
+
|
|
15
|
+
## Sequence
|
|
16
|
+
|
|
17
|
+
**1. Review what's queued.**
|
|
18
|
+
|
|
19
|
+
Run `/gflow:changelog` — confirm the `[Unreleased]` block is non-empty and accurate before proceeding.
|
|
20
|
+
|
|
21
|
+
**2. Verify clean working tree.**
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
git status --short
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Must be empty. If not, abort and tell the user to commit or stash first.
|
|
28
|
+
|
|
29
|
+
**3. Verify on `main`, up-to-date with `origin/main`.**
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
git rev-parse --abbrev-ref HEAD # must be "main"
|
|
33
|
+
git fetch origin
|
|
34
|
+
git rev-list HEAD..origin/main # must be empty
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**4. Run quality gates.**
|
|
38
|
+
|
|
39
|
+
Run `/gflow:check` — all gates must pass. Abort if any fail.
|
|
40
|
+
|
|
41
|
+
**5. Bump version** in `pyproject.toml`:
|
|
42
|
+
|
|
43
|
+
```toml
|
|
44
|
+
[project]
|
|
45
|
+
version = "<NEW_VERSION>"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**6. Bump package version** in `src/gflow_cli/__init__.py`:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
__version__ = "<NEW_VERSION>"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**7. Update version assertion tests** if present:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
rg -n "__version__|<OLD_VERSION>|version assertion" tests src pyproject.toml
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**8. Migrate CHANGELOG.**
|
|
61
|
+
|
|
62
|
+
- Move all entries under `## [Unreleased]` to a new `## [<NEW_VERSION>] — YYYY-MM-DD` section.
|
|
63
|
+
- Leave `## [Unreleased]` empty.
|
|
64
|
+
- Update the link footer:
|
|
65
|
+
```
|
|
66
|
+
[Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v<NEW_VERSION>...HEAD
|
|
67
|
+
[<NEW_VERSION>]: https://github.com/ffroliva/gflow-cli/releases/tag/v<NEW_VERSION>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**9. Review commands for staleness.**
|
|
71
|
+
|
|
72
|
+
Scan `.claude/commands/gflow/` — check if any command references a phase, file path, or behaviour that the release changes. Update in the same commit if so.
|
|
73
|
+
|
|
74
|
+
**10. Commit the release prep.**
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
git add pyproject.toml src/gflow_cli/__init__.py CHANGELOG.md tests
|
|
78
|
+
git commit -m "chore(release): v<NEW_VERSION>"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**11. Tag.** Use `-s` for a signed annotated tag so GitHub shows the **"Verified"** badge AND `.github/workflows/release.yml` passes the signed-tag gate (lightweight or unsigned tags are rejected).
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
git tag -s v<NEW_VERSION> -m "v<NEW_VERSION>"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Requires a GPG or SSH signing key registered in your GitHub account settings.
|
|
88
|
+
Run `git config --global user.signingkey` to confirm a key is set.
|
|
89
|
+
If signing is not available in the current environment, create the tag on
|
|
90
|
+
your local machine and push it: `git push origin v<NEW_VERSION>`.
|
|
91
|
+
|
|
92
|
+
**12. Push commit + tag.**
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
git push origin main
|
|
96
|
+
git push origin v<NEW_VERSION>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**13. Report.**
|
|
100
|
+
|
|
101
|
+
Tell the user:
|
|
102
|
+
- The pushed tag triggers `.github/workflows/release.yml`.
|
|
103
|
+
- Watch <https://github.com/ffroliva/gflow-cli/actions> for the release workflow.
|
|
104
|
+
- On success: PyPI publish + GitHub Release with auto-generated notes.
|
|
105
|
+
- On failure (most common: PyPI Trusted Publishing not yet configured): point to <https://pypi.org/manage/account/publishing/>.
|
|
106
|
+
|
|
107
|
+
## Critical reminders
|
|
108
|
+
|
|
109
|
+
- **NEVER** add `Co-Authored-By: Claude` (or any AI co-author) to the release commit.
|
|
110
|
+
- **NEVER** force-push a release tag once it's on GitHub. Ship a PATCH fix instead.
|
|
111
|
+
- **NEVER** `--no-verify` past hooks. Fix the underlying issue.
|
|
112
|
+
- If quality gates fail at step 4, **STOP**. Surface the failures to the user.
|
|
113
|
+
|
|
114
|
+
## See also
|
|
115
|
+
|
|
116
|
+
- [RELEASE.md](../../../RELEASE.md) — full release protocol, prerelease policy, and checklist
|
|
117
|
+
- [README § Releases](../../../README.md#releases) — release policy and cadence
|
|
118
|
+
- [PLAN § Phase 5](../../../PLAN.md#phase-5--public-alpha-release-on-pypi) — first-release exit criteria
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# CODEOWNERS — https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
|
|
2
|
+
#
|
|
3
|
+
# These owners are automatically requested for review on every PR that touches
|
|
4
|
+
# the matched paths. Ownership does not prevent external contributors from
|
|
5
|
+
# opening PRs — it ensures a maintainer is always in the review loop.
|
|
6
|
+
|
|
7
|
+
# Global fallback — everything not matched below
|
|
8
|
+
* @ffroliva
|
|
9
|
+
|
|
10
|
+
# Core source
|
|
11
|
+
/src/ @ffroliva
|
|
12
|
+
|
|
13
|
+
# CI and security gates — changes here require extra care
|
|
14
|
+
/.github/ @ffroliva
|
|
15
|
+
/scripts/ci/ @ffroliva
|
|
16
|
+
/.pre-commit-config.yaml @ffroliva
|
|
17
|
+
/.gitleaks.toml @ffroliva
|
|
18
|
+
/.secrets.baseline @ffroliva
|
|
19
|
+
/.gitignore @ffroliva
|
|
20
|
+
|
|
21
|
+
# Auth handling — sensitive, never bypass review
|
|
22
|
+
/src/gflow_cli/auth.py @ffroliva
|
|
23
|
+
/src/gflow_cli/auth/ @ffroliva
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<!-- What changed and why? Link issues with "Fixes #123" when applicable. -->
|
|
4
|
+
|
|
5
|
+
## Validation
|
|
6
|
+
|
|
7
|
+
<!-- List the focused commands you ran, plus any checks you could not run. -->
|
|
8
|
+
|
|
9
|
+
- [ ] Focused tests added or updated for behavior changes
|
|
10
|
+
- [ ] `uv run ruff check src tests`
|
|
11
|
+
- [ ] `uv run pyright src`
|
|
12
|
+
- [ ] Relevant pytest command:
|
|
13
|
+
|
|
14
|
+
## Contribution Checklist
|
|
15
|
+
|
|
16
|
+
- [ ] This PR targets `develop`, unless it is a release or emergency fix
|
|
17
|
+
- [ ] My commits use my real Git identity or GitHub noreply email
|
|
18
|
+
- [ ] External contribution commits include `Signed-off-by:` (`git commit -s`)
|
|
19
|
+
- [ ] I did not include secrets, cookies, account tokens, signed URLs, or private captured data
|
|
20
|
+
- [ ] I reviewed any AI-assisted changes before submitting
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Copilot Code Review Instructions
|
|
2
|
+
|
|
3
|
+
Review this repository as a Python CLI that automates browser-authenticated
|
|
4
|
+
Google Flow workflows. Treat auth, browser automation, CI, release, and secret
|
|
5
|
+
handling changes as high-risk even when the diff is small.
|
|
6
|
+
|
|
7
|
+
For pull request reviews:
|
|
8
|
+
|
|
9
|
+
- Check that PRs target `develop`, unless they are release PRs.
|
|
10
|
+
- Flag unclear contributor provenance, missing DCO sign-off, placeholder author
|
|
11
|
+
emails, and any copied private data.
|
|
12
|
+
- Look for leaked tokens, cookies, signed URLs, local profile paths, and captured
|
|
13
|
+
Google/Flow request data.
|
|
14
|
+
- For auth/browser changes, check that the implementation preserves profile
|
|
15
|
+
isolation, does not weaken local path boundaries, and avoids remote debugging
|
|
16
|
+
unless explicitly documented.
|
|
17
|
+
- For CI changes, check forked-PR secret behavior and avoid recommending
|
|
18
|
+
`pull_request_target` for jobs that checkout or execute contributor code.
|
|
19
|
+
- For behavior changes, expect focused tests and docs/changelog updates.
|
|
20
|
+
- Keep findings concrete: reference files/lines, explain the user-visible risk,
|
|
21
|
+
and separate blocking issues from cosmetic suggestions.
|
|
22
|
+
|
|
23
|
+
Do not approve pull requests. Copilot review is advisory; maintainer approval is
|
|
24
|
+
still required.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Dependabot configuration
|
|
2
|
+
# Docs: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
3
|
+
|
|
4
|
+
version: 2
|
|
5
|
+
updates:
|
|
6
|
+
# Python dependencies (pip/uv — Dependabot reads pyproject.toml)
|
|
7
|
+
- package-ecosystem: "pip"
|
|
8
|
+
directory: "/"
|
|
9
|
+
schedule:
|
|
10
|
+
interval: "weekly"
|
|
11
|
+
day: "monday"
|
|
12
|
+
time: "08:00"
|
|
13
|
+
timezone: "Europe/Lisbon"
|
|
14
|
+
open-pull-requests-limit: 5
|
|
15
|
+
labels:
|
|
16
|
+
- "dependencies"
|
|
17
|
+
- "python"
|
|
18
|
+
ignore:
|
|
19
|
+
# Playwright has its own browser download step; pin manually.
|
|
20
|
+
- dependency-name: "playwright"
|
|
21
|
+
update-types: ["version-update:semver-major"]
|
|
22
|
+
|
|
23
|
+
# GitHub Actions
|
|
24
|
+
- package-ecosystem: "github-actions"
|
|
25
|
+
directory: "/"
|
|
26
|
+
schedule:
|
|
27
|
+
interval: "weekly"
|
|
28
|
+
day: "monday"
|
|
29
|
+
time: "08:00"
|
|
30
|
+
timezone: "Europe/Lisbon"
|
|
31
|
+
open-pull-requests-limit: 5
|
|
32
|
+
labels:
|
|
33
|
+
- "dependencies"
|
|
34
|
+
- "github-actions"
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [develop, main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
env:
|
|
9
|
+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
# ── Security gate: runs first, on every push/PR, never skippable ──────────
|
|
13
|
+
secrets-scan:
|
|
14
|
+
name: Secret scan (gitleaks)
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v6
|
|
18
|
+
with:
|
|
19
|
+
fetch-depth: 0 # full history so gitleaks can diff against base
|
|
20
|
+
|
|
21
|
+
- name: Run gitleaks
|
|
22
|
+
uses: gitleaks/gitleaks-action@v2
|
|
23
|
+
env:
|
|
24
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
25
|
+
|
|
26
|
+
# ── Main test matrix ──────────────────────────────────────────────────────
|
|
27
|
+
test:
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
strategy:
|
|
30
|
+
matrix:
|
|
31
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@v6
|
|
34
|
+
|
|
35
|
+
- name: Install uv
|
|
36
|
+
uses: astral-sh/setup-uv@v7
|
|
37
|
+
|
|
38
|
+
- name: Set up Python
|
|
39
|
+
run: uv python install ${{ matrix.python-version }}
|
|
40
|
+
|
|
41
|
+
- name: Install deps
|
|
42
|
+
run: uv sync --extra dev
|
|
43
|
+
|
|
44
|
+
- name: Repo hygiene (no artefacts, no hardcoded paths)
|
|
45
|
+
run: uv run python scripts/ci/check_repo_hygiene.py
|
|
46
|
+
|
|
47
|
+
- name: Lint
|
|
48
|
+
run: uv run ruff check src tests
|
|
49
|
+
|
|
50
|
+
- name: Format check
|
|
51
|
+
run: uv run ruff format --check src tests
|
|
52
|
+
|
|
53
|
+
- name: Type check
|
|
54
|
+
run: uv run pyright src
|
|
55
|
+
|
|
56
|
+
- name: Test (smoke only) + coverage
|
|
57
|
+
# e2e tests (tests/e2e/) require a logged-in Chromium profile
|
|
58
|
+
# and live Flow auth — never runnable in CI. They self-mark with
|
|
59
|
+
# `pytestmark = pytest.mark.e2e` (file-level) and are opt-in via
|
|
60
|
+
# `-m e2e` per their module docstring. `live` marker is reserved for
|
|
61
|
+
# `GFLOW_LIVE=1` tests that hit the real Flow API. Both are excluded
|
|
62
|
+
# from the default smoke run; `tests/smoke/test_real_flow.py` already
|
|
63
|
+
# self-skips via `pytest.mark.skipif(GFLOW_E2E != "1")`.
|
|
64
|
+
run: uv run python -m pytest -q -m "not e2e and not live" --cov=gflow_cli --cov-report=xml
|
|
65
|
+
|
|
66
|
+
# Upload coverage XML so the sonar job can consume it
|
|
67
|
+
- name: Upload coverage report
|
|
68
|
+
if: matrix.python-version == '3.11'
|
|
69
|
+
uses: actions/upload-artifact@v7
|
|
70
|
+
with:
|
|
71
|
+
name: coverage-xml
|
|
72
|
+
path: coverage.xml
|
|
73
|
+
retention-days: 1
|
|
74
|
+
|
|
75
|
+
# ── SonarCloud analysis ───────────────────────────────────────────────────
|
|
76
|
+
sonar:
|
|
77
|
+
name: SonarCloud analysis
|
|
78
|
+
runs-on: ubuntu-latest
|
|
79
|
+
needs: test # wait for tests + coverage report
|
|
80
|
+
# Forked pull_request runs do not receive repository secrets, so SONAR_TOKEN
|
|
81
|
+
# is empty there and the scanner fails before analysis. Keep SonarCloud on
|
|
82
|
+
# trusted pushes/internal PRs where the token is available.
|
|
83
|
+
if: >
|
|
84
|
+
always() &&
|
|
85
|
+
(
|
|
86
|
+
github.event_name != 'pull_request' ||
|
|
87
|
+
github.event.pull_request.head.repo.full_name == github.repository
|
|
88
|
+
)
|
|
89
|
+
steps:
|
|
90
|
+
- uses: actions/checkout@v6
|
|
91
|
+
with:
|
|
92
|
+
fetch-depth: 0 # shallow clones break blame / new-code detection
|
|
93
|
+
|
|
94
|
+
- name: Download coverage report
|
|
95
|
+
uses: actions/download-artifact@v8
|
|
96
|
+
with:
|
|
97
|
+
name: coverage-xml
|
|
98
|
+
continue-on-error: true # graceful if coverage upload was skipped
|
|
99
|
+
|
|
100
|
+
- name: SonarCloud scan
|
|
101
|
+
uses: SonarSource/sonarcloud-github-action@master
|
|
102
|
+
env:
|
|
103
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # PR decoration
|
|
104
|
+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # set in repo → Settings → Secrets
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
name: External PR Triage
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request_target:
|
|
5
|
+
types: [opened, reopened, synchronize, ready_for_review, edited]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
issues: write
|
|
10
|
+
pull-requests: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
triage:
|
|
14
|
+
name: Label and route external PRs
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- name: Triage external pull request
|
|
18
|
+
uses: actions/github-script@v7
|
|
19
|
+
with:
|
|
20
|
+
script: |
|
|
21
|
+
const pr = context.payload.pull_request;
|
|
22
|
+
if (!pr) {
|
|
23
|
+
core.info("No pull request payload; nothing to do.");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const owner = context.repo.owner;
|
|
28
|
+
const repo = context.repo.repo;
|
|
29
|
+
const issue_number = pr.number;
|
|
30
|
+
const isBot = pr.user?.type === "Bot";
|
|
31
|
+
const trustedAssociations = new Set(["OWNER", "MEMBER", "COLLABORATOR"]);
|
|
32
|
+
const isFork = pr.head.repo.full_name !== pr.base.repo.full_name;
|
|
33
|
+
const isExternal = isFork || !trustedAssociations.has(pr.author_association);
|
|
34
|
+
|
|
35
|
+
if (isBot) {
|
|
36
|
+
core.info("Bot PR; skipping human external-contribution triage.");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!isExternal) {
|
|
41
|
+
core.info("PR is not external; skipping external triage.");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const labels = [
|
|
46
|
+
{
|
|
47
|
+
name: "external-contribution",
|
|
48
|
+
color: "0e8a16",
|
|
49
|
+
description: "Pull request from a non-maintainer or fork",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "needs-maintainer-review",
|
|
53
|
+
color: "fbca04",
|
|
54
|
+
description: "Requires maintainer review before merge",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "needs-copilot-review",
|
|
58
|
+
color: "5319e7",
|
|
59
|
+
description: "Ask GitHub Copilot for advisory code review",
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
for (const label of labels) {
|
|
64
|
+
try {
|
|
65
|
+
await github.rest.issues.createLabel({ owner, repo, ...label });
|
|
66
|
+
} catch (error) {
|
|
67
|
+
if (error.status !== 422) {
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
await github.rest.issues.addLabels({
|
|
74
|
+
owner,
|
|
75
|
+
repo,
|
|
76
|
+
issue_number,
|
|
77
|
+
labels: labels.map((label) => label.name),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
await github.rest.pulls.requestReviewers({
|
|
82
|
+
owner,
|
|
83
|
+
repo,
|
|
84
|
+
pull_number: issue_number,
|
|
85
|
+
reviewers: ["ffroliva"],
|
|
86
|
+
});
|
|
87
|
+
} catch (error) {
|
|
88
|
+
core.warning(`Could not request maintainer review: ${error.message}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const marker = "<!-- gflow-cli-external-pr-triage -->";
|
|
92
|
+
const body = `${marker}
|
|
93
|
+
Thanks for the contribution. This PR has been marked as an external contribution and routed for maintainer review.
|
|
94
|
+
|
|
95
|
+
Before merge, please make sure:
|
|
96
|
+
|
|
97
|
+
- The PR targets \`develop\`.
|
|
98
|
+
- Commits use a real Git identity or GitHub noreply email.
|
|
99
|
+
- External commits include a DCO sign-off: \`git commit -s\`.
|
|
100
|
+
- The PR does not include secrets, cookies, account tokens, signed URLs, or private captured data.
|
|
101
|
+
- Focused tests/docs are included for behavior changes.
|
|
102
|
+
|
|
103
|
+
GitHub Copilot code review may be requested as an advisory first pass, but maintainer approval is still required.`;
|
|
104
|
+
|
|
105
|
+
const comments = await github.paginate(github.rest.issues.listComments, {
|
|
106
|
+
owner,
|
|
107
|
+
repo,
|
|
108
|
+
issue_number,
|
|
109
|
+
per_page: 100,
|
|
110
|
+
});
|
|
111
|
+
const existing = comments.find((comment) => comment.body?.includes(marker));
|
|
112
|
+
if (existing) {
|
|
113
|
+
await github.rest.issues.updateComment({
|
|
114
|
+
owner,
|
|
115
|
+
repo,
|
|
116
|
+
comment_id: existing.id,
|
|
117
|
+
body,
|
|
118
|
+
});
|
|
119
|
+
} else {
|
|
120
|
+
await github.rest.issues.createComment({
|
|
121
|
+
owner,
|
|
122
|
+
repo,
|
|
123
|
+
issue_number,
|
|
124
|
+
body,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
@@ -18,16 +18,31 @@ jobs:
|
|
|
18
18
|
env:
|
|
19
19
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
20
20
|
steps:
|
|
21
|
-
- uses: actions/checkout@
|
|
21
|
+
- uses: actions/checkout@v6
|
|
22
22
|
with:
|
|
23
23
|
fetch-depth: 0
|
|
24
24
|
|
|
25
25
|
- name: Install uv
|
|
26
|
-
uses: astral-sh/setup-uv@
|
|
26
|
+
uses: astral-sh/setup-uv@v7
|
|
27
27
|
|
|
28
28
|
- name: Set up Python
|
|
29
29
|
run: uv python install 3.12
|
|
30
30
|
|
|
31
|
+
- name: Verify tag is signed
|
|
32
|
+
run: |
|
|
33
|
+
TAG=${GITHUB_REF_NAME}
|
|
34
|
+
# Lightweight tags resolve directly to a commit, not a tag object.
|
|
35
|
+
TYPE=$(git cat-file -t "$TAG")
|
|
36
|
+
if [ "$TYPE" != "tag" ]; then
|
|
37
|
+
echo "::error::$TAG is a lightweight tag. Use 'git tag -s' to create a signed annotated tag."
|
|
38
|
+
exit 1
|
|
39
|
+
fi
|
|
40
|
+
# Annotated but unsigned tags have no signature header in the object.
|
|
41
|
+
if ! git cat-file -p "$TAG" | grep -qE "BEGIN (PGP|SSH) SIGNATURE"; then
|
|
42
|
+
echo "::error::$TAG is not signed. Use 'git tag -s' when cutting releases."
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
|
|
31
46
|
- name: Verify tag matches pyproject version
|
|
32
47
|
run: |
|
|
33
48
|
TAG=${GITHUB_REF_NAME#v}
|
|
@@ -46,7 +61,7 @@ jobs:
|
|
|
46
61
|
# Configure once at https://pypi.org/manage/account/publishing/
|
|
47
62
|
|
|
48
63
|
- name: Create GitHub Release
|
|
49
|
-
uses: softprops/action-gh-release@
|
|
64
|
+
uses: softprops/action-gh-release@v3
|
|
50
65
|
with:
|
|
51
66
|
generate_release_notes: true
|
|
52
67
|
files: dist/*
|
|
@@ -43,12 +43,25 @@ secrets.json # generic secrets file
|
|
|
43
43
|
# Generated outputs
|
|
44
44
|
out/
|
|
45
45
|
tmp/
|
|
46
|
+
gflow-output/
|
|
46
47
|
*.mp4
|
|
47
48
|
*.png
|
|
49
|
+
*.jpg
|
|
50
|
+
*.jpeg
|
|
48
51
|
!docs/**/*.png # docs images are OK
|
|
49
52
|
!tests/fixtures/**/*.png
|
|
53
|
+
!test_assets/fixtures/**/*.jpg
|
|
54
|
+
!test_assets/fixtures/**/*.jpeg
|
|
50
55
|
samples/*.captured.json # sandbox-recorded API exchanges may contain PII
|
|
51
56
|
|
|
57
|
+
# CDP browser session lock files (contain PID, port, profile name)
|
|
58
|
+
.gflow-cdp.lock
|
|
59
|
+
**/.gflow-cdp.lock
|
|
60
|
+
|
|
61
|
+
# Runtime artefact dirs written by smoke/debug scripts — belong under tmp/ only
|
|
62
|
+
test_assets/smoke_*/
|
|
63
|
+
test_assets/debug_*/
|
|
64
|
+
|
|
52
65
|
# Live Flow traffic captures — NEVER commit (contain real Bearer tokens / API keys).
|
|
53
66
|
# Diagnostic scripts MUST default-write here, NOT to samples/captured/.
|
|
54
67
|
# Sanitised reference samples (no secrets) can still live under samples/captured/.
|