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.
Files changed (233) hide show
  1. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/.claude/README.md +8 -3
  2. gflow_cli-0.7.0/.claude/commands/gflow/changelog.md +21 -0
  3. gflow_cli-0.7.0/.claude/commands/gflow/check.md +48 -0
  4. gflow_cli-0.7.0/.claude/commands/gflow/known-issues.md +20 -0
  5. gflow_cli-0.7.0/.claude/commands/gflow/plan.md +39 -0
  6. gflow_cli-0.7.0/.claude/commands/gflow/release.md +118 -0
  7. gflow_cli-0.7.0/.github/CODEOWNERS +23 -0
  8. gflow_cli-0.7.0/.github/PULL_REQUEST_TEMPLATE.md +20 -0
  9. gflow_cli-0.7.0/.github/copilot-instructions.md +24 -0
  10. gflow_cli-0.7.0/.github/dependabot.yml +34 -0
  11. gflow_cli-0.7.0/.github/workflows/ci.yml +104 -0
  12. gflow_cli-0.7.0/.github/workflows/external-pr-triage.yml +126 -0
  13. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/.github/workflows/release.yml +18 -3
  14. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/.gitignore +13 -0
  15. gflow_cli-0.7.0/.gitleaks.toml +33 -0
  16. gflow_cli-0.7.0/.pre-commit-config.yaml +38 -0
  17. gflow_cli-0.7.0/.secrets.baseline +152 -0
  18. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/CHANGELOG.md +151 -1
  19. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/CLAUDE.md +30 -18
  20. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/CONTRIBUTING.md +47 -14
  21. gflow_cli-0.7.0/KNOWN_ISSUES.md +326 -0
  22. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/PKG-INFO +25 -44
  23. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/PLAN.md +215 -1
  24. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/README.md +24 -43
  25. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/RELEASE.md +2 -2
  26. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/ARCHITECTURE.md +5 -0
  27. gflow_cli-0.7.0/docs/DEBUGGING.md +183 -0
  28. gflow_cli-0.7.0/docs/DEVELOPMENT.md +125 -0
  29. gflow_cli-0.7.0/docs/GITHUB.md +139 -0
  30. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/INDEX.md +29 -0
  31. gflow_cli-0.7.0/docs/LIVE_VERIFICATION_v0.7.0.md +110 -0
  32. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/SECURITY.md +37 -1
  33. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/USAGE.md +64 -10
  34. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/USER_GUIDE.md +248 -0
  35. gflow_cli-0.7.0/docs/superpowers/2026-05-17-issue-15-handover.md +59 -0
  36. gflow_cli-0.7.0/docs/superpowers/plans/2026-05-17-e2e-test-coverage.md +463 -0
  37. gflow_cli-0.7.0/docs/superpowers/plans/2026-05-17-issue-15-auth-verification-fix.md +1449 -0
  38. gflow_cli-0.7.0/docs/superpowers/plans/2026-05-17-issue-15-i2v-bearer-auth.md +811 -0
  39. gflow_cli-0.7.0/docs/superpowers/plans/2026-05-17-issue-15-orchestration.md +118 -0
  40. gflow_cli-0.7.0/docs/superpowers/plans/2026-05-18-video-phase0-submit-spike.md +697 -0
  41. gflow_cli-0.7.0/docs/superpowers/plans/2026-05-19-video-phase-a-execution-state.md +64 -0
  42. gflow_cli-0.7.0/docs/superpowers/plans/2026-05-19-video-phase-a-orchestration.md +164 -0
  43. gflow_cli-0.7.0/docs/superpowers/plans/2026-05-19-video-phase-a-t2v.md +2083 -0
  44. gflow_cli-0.7.0/docs/superpowers/specs/2026-05-17-e2e-test-coverage-design.md +190 -0
  45. gflow_cli-0.7.0/docs/superpowers/specs/2026-05-17-i2v-uploadimage-401-bearer-auth-design.md +330 -0
  46. gflow_cli-0.7.0/docs/superpowers/specs/2026-05-17-issue-15-auth-verification-fix-design.md +485 -0
  47. gflow_cli-0.7.0/docs/superpowers/specs/2026-05-17-issue-15-root-cause-findings.md +87 -0
  48. gflow_cli-0.7.0/docs/superpowers/specs/2026-05-18-ui-automation-video-generation-design.md +739 -0
  49. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/pyproject.toml +2 -1
  50. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/samples/captured/02_batchAsyncGenerateVideoText.json +3 -3
  51. gflow_cli-0.7.0/samples/captured/08_batchAsyncGenerateVideoStartAndEndImage.json +144 -0
  52. gflow_cli-0.7.0/samples/captured/09_batchAsyncGenerateVideoReferenceImages.json +136 -0
  53. gflow_cli-0.7.0/samples/captured/10_batchCheckAsyncVideoGenerationStatus_successful.json +90 -0
  54. gflow_cli-0.7.0/samples/captured/11_batchCheckAsyncVideoGenerationStatus_failed.json +97 -0
  55. gflow_cli-0.7.0/scripts/ci/check_repo_hygiene.py +141 -0
  56. gflow_cli-0.7.0/scripts/debug_editor.py +69 -0
  57. gflow_cli-0.7.0/scripts/debug_gen_settings.py +83 -0
  58. gflow_cli-0.7.0/scripts/debug_settings.py +69 -0
  59. gflow_cli-0.7.0/scripts/dev/active_plan.py +188 -0
  60. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/scripts/diag_capture_flow_traffic.py +1 -1
  61. gflow_cli-0.7.0/scripts/smoke_video_editor.py +874 -0
  62. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/scripts/smoke_worker_style.py +188 -38
  63. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/scripts/verify_chrome_auth_viability.py +9 -9
  64. gflow_cli-0.7.0/sonar-project.properties +35 -0
  65. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/__init__.py +1 -1
  66. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/__init__.py +1 -3
  67. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/_retry.py +2 -1
  68. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/client.py +178 -119
  69. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/dto.py +0 -67
  70. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/image.py +4 -0
  71. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/recaptcha.py +1 -1
  72. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/base.py +2 -2
  73. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/experimental/bearer.py +7 -3
  74. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/experimental/evaluate_fetch.py +7 -1
  75. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/experimental/sapisidhash.py +6 -1
  76. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/ui_automation.py +499 -60
  77. gflow_cli-0.7.0/src/gflow_cli/api/transports/ui_automation_video.py +498 -0
  78. gflow_cli-0.7.0/src/gflow_cli/api/video.py +156 -0
  79. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/auth/__init__.py +2 -2
  80. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/auth/internal_chromium.py +56 -27
  81. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/auth/real_chrome.py +72 -44
  82. gflow_cli-0.7.0/src/gflow_cli/auth/verification.py +228 -0
  83. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/browser_manager.py +93 -111
  84. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/cli_image.py +46 -30
  85. gflow_cli-0.7.0/src/gflow_cli/cli_video.py +95 -0
  86. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/config.py +7 -6
  87. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/errors.py +58 -4
  88. gflow_cli-0.7.0/src/gflow_cli/exceptions.py +25 -0
  89. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/image_batch.py +0 -1
  90. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/manifest.py +18 -17
  91. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tasks/lessons.md +34 -0
  92. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_client.py +90 -4
  93. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_client_image.py +116 -65
  94. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_concurrency.py +1 -0
  95. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_dto.py +1 -38
  96. gflow_cli-0.7.0/tests/api/test_video.py +213 -0
  97. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/test_evaluate_fetch.py +2 -2
  98. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/test_ui_automation.py +291 -40
  99. gflow_cli-0.7.0/tests/api/transports/test_ui_automation_video.py +392 -0
  100. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/auth/strategies/test_strategies.py +150 -56
  101. gflow_cli-0.7.0/tests/auth/test_verification.py +301 -0
  102. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/cli/test_error_handling.py +17 -1
  103. gflow_cli-0.7.0/tests/e2e/conftest.py +67 -0
  104. gflow_cli-0.7.0/tests/e2e/test_auth_verification_e2e.py +65 -0
  105. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/e2e/test_transports_e2e.py +73 -1
  106. gflow_cli-0.7.0/tests/e2e/test_video_t2v_e2e.py +139 -0
  107. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/conftest.py +0 -2
  108. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/test_step_collision_guard.py +2 -4
  109. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_browser_manager.py +9 -0
  110. gflow_cli-0.7.0/tests/test_cli_video.py +44 -0
  111. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_config.py +6 -5
  112. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_errors.py +28 -0
  113. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_smoke.py +2 -1
  114. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/uv.lock +184 -1
  115. gflow_cli-0.6.0a4/.claude/commands/release.md +0 -97
  116. gflow_cli-0.6.0a4/.github/workflows/ci.yml +0 -42
  117. gflow_cli-0.6.0a4/KNOWN_ISSUES.md +0 -184
  118. gflow_cli-0.6.0a4/scripts/smoke_e2e.py +0 -78
  119. gflow_cli-0.6.0a4/src/gflow_cli/api/video.py +0 -112
  120. gflow_cli-0.6.0a4/src/gflow_cli/cli_video.py +0 -341
  121. gflow_cli-0.6.0a4/tests/api/test_client_generate_video.py +0 -93
  122. gflow_cli-0.6.0a4/tests/api/test_video.py +0 -83
  123. gflow_cli-0.6.0a4/tests/features/test_video_steps.py +0 -253
  124. gflow_cli-0.6.0a4/tests/features/video.feature +0 -27
  125. gflow_cli-0.6.0a4/tests/test_cli_video.py +0 -220
  126. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/.env.template +0 -0
  127. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/.gitattributes +0 -0
  128. {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
  129. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/CONFIGURATION.md +0 -0
  130. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/DISCLAIMER.md +0 -0
  131. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/LICENSE +0 -0
  132. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/AUTHENTICATION.md +0 -0
  133. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/CONFIGURATION.md +0 -0
  134. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/assets/example-run.gif +0 -0
  135. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-09-image-mvp-orchestration.md +0 -0
  136. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-09-image-mvp.md +0 -0
  137. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-09-video-mvp-orchestration.md +0 -0
  138. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-09-video-mvp.md +0 -0
  139. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-10-phase-4-hardening-orchestration.md +0 -0
  140. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-10-phase-4-hardening.md +0 -0
  141. {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
  142. {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
  143. {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
  144. {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
  145. {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
  146. {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
  147. {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
  148. {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
  149. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-14-shell-multi-prompt/PLAN.md +0 -0
  150. {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
  151. {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
  152. {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
  153. {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
  154. {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
  155. {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
  156. {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
  157. {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
  158. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/PLAN.md +0 -0
  159. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/plans/2026-05-15-auth-login-real-chrome/orchestration.md +0 -0
  160. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/specs/2026-05-10-phase-4-hardening-design.md +0 -0
  161. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/specs/2026-05-14-shell-multi-prompt-design.md +0 -0
  162. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/specs/2026-05-15-auth-login-real-chrome-design.md +0 -0
  163. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/docs/superpowers/verifications/2026-05-11-phase-4-stage-g.md +0 -0
  164. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/examples/README.md +0 -0
  165. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/examples/batch_from_config.py +0 -0
  166. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/examples/multi_prompt_t2i.py +0 -0
  167. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/examples/sample_config.json +0 -0
  168. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/examples/sample_prompts.txt +0 -0
  169. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/examples/single_image_t2i.py +0 -0
  170. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/samples/README.md +0 -0
  171. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/samples/captured/01_upload_image.json +0 -0
  172. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
  173. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/samples/captured/04_archive_workflow.json +0 -0
  174. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/samples/captured/05_createProject.json +0 -0
  175. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/samples/captured/06_batchGenerateImages.json +0 -0
  176. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/samples/captured/07_batchGenerateImages_seeded.json +0 -0
  177. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/scripts/diag_recaptcha_mint.py +0 -0
  178. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/scripts/record_demo.ps1 +0 -0
  179. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/scripts/smoke_image.py +0 -0
  180. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/scripts/smoke_real_chrome_image.py +0 -0
  181. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/skills/README.md +0 -0
  182. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/skills/gflow-cli/SKILL.md +0 -0
  183. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/__main__.py +0 -0
  184. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/_cli_helpers.py +0 -0
  185. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/routes.py +0 -0
  186. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/__init__.py +0 -0
  187. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/_common.py +0 -0
  188. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/_fingerprint.py +0 -0
  189. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/api/transports/experimental/__init__.py +0 -0
  190. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/auth/base.py +0 -0
  191. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/auth/factory.py +0 -0
  192. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/auth/strategies.py +0 -0
  193. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/cli.py +0 -0
  194. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/cli_run.py +0 -0
  195. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/observability.py +0 -0
  196. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/paths.py +0 -0
  197. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/src/gflow_cli/profile_store.py +0 -0
  198. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/__init__.py +0 -0
  199. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/__init__.py +0 -0
  200. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_image.py +0 -0
  201. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_image_dto.py +0 -0
  202. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_recaptcha.py +0 -0
  203. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_retry.py +0 -0
  204. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/test_routes.py +0 -0
  205. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/__init__.py +0 -0
  206. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/test_base.py +0 -0
  207. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/test_bearer.py +0 -0
  208. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/test_common.py +0 -0
  209. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/test_factory.py +0 -0
  210. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/test_fingerprint.py +0 -0
  211. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/api/transports/test_sapisidhash.py +0 -0
  212. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/auth/strategies/test_factory.py +0 -0
  213. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/cli/__init__.py +0 -0
  214. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/cli/test_cli_image.py +0 -0
  215. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/cli/test_cli_run.py +1 -1
  216. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/cli/test_helpers.py +0 -0
  217. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/cli/test_t2i_multi_prompt.py +0 -0
  218. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/conftest.py +0 -0
  219. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/e2e/__init__.py +0 -0
  220. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/__init__.py +0 -0
  221. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/auth.feature +0 -0
  222. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/auth_login.feature +0 -0
  223. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/image.feature +0 -0
  224. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/test_auth_login_steps.py +0 -0
  225. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/test_auth_steps.py +0 -0
  226. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/features/test_image_steps.py +0 -0
  227. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/smoke/__init__.py +0 -0
  228. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/smoke/test_real_flow.py +0 -0
  229. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_auth.py +0 -0
  230. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_manifest.py +0 -0
  231. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_observability.py +0 -0
  232. {gflow_cli-0.6.0a4 → gflow_cli-0.7.0}/tests/test_paths.py +0 -0
  233. {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
- └── release.md ← `/release` automates the version-bump + tag + push flow
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/`. 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.
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@v4
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@v3
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@v2
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/.