gflow-cli 0.4.0a2__tar.gz → 0.5.0a1__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 (141) hide show
  1. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/.claude/commands/release.md +21 -10
  2. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/.github/workflows/ci.yml +8 -1
  3. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/.github/workflows/release.yml +5 -1
  4. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/.gitignore +7 -0
  5. gflow_cli-0.5.0a1/.planning/todos/pending/2026-05-11-add-project-logo-and-docs-site-promotion-plan.md +38 -0
  6. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/CHANGELOG.md +90 -0
  7. gflow_cli-0.5.0a1/CONFIGURATION.md +68 -0
  8. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/PKG-INFO +22 -10
  9. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/README.md +21 -9
  10. gflow_cli-0.5.0a1/RELEASE.md +97 -0
  11. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/docs/AUTHENTICATION.md +1 -1
  12. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/docs/INDEX.md +2 -0
  13. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/docs/SECURITY.md +1 -1
  14. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/docs/USAGE.md +61 -0
  15. gflow_cli-0.5.0a1/docs/superpowers/verifications/2026-05-11-phase-4-stage-g.md +123 -0
  16. gflow_cli-0.5.0a1/examples/README.md +57 -0
  17. gflow_cli-0.5.0a1/examples/batch_from_config.py +99 -0
  18. gflow_cli-0.5.0a1/examples/sample_config.json +18 -0
  19. gflow_cli-0.5.0a1/examples/single_image_t2i.py +135 -0
  20. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/pyproject.toml +5 -1
  21. gflow_cli-0.5.0a1/scripts/diag_capture_flow_traffic.py +125 -0
  22. gflow_cli-0.5.0a1/scripts/diag_recaptcha_mint.py +77 -0
  23. gflow_cli-0.5.0a1/scripts/smoke_real_chrome_image.py +416 -0
  24. gflow_cli-0.5.0a1/scripts/smoke_worker_style.py +415 -0
  25. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/__init__.py +1 -1
  26. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/api/client.py +100 -57
  27. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/api/image.py +13 -3
  28. gflow_cli-0.5.0a1/src/gflow_cli/api/transports/__init__.py +83 -0
  29. gflow_cli-0.5.0a1/src/gflow_cli/api/transports/_common.py +105 -0
  30. gflow_cli-0.5.0a1/src/gflow_cli/api/transports/_fingerprint.py +140 -0
  31. gflow_cli-0.5.0a1/src/gflow_cli/api/transports/base.py +59 -0
  32. gflow_cli-0.5.0a1/src/gflow_cli/api/transports/experimental/__init__.py +28 -0
  33. gflow_cli-0.5.0a1/src/gflow_cli/api/transports/experimental/bearer.py +341 -0
  34. gflow_cli-0.5.0a1/src/gflow_cli/api/transports/experimental/evaluate_fetch.py +311 -0
  35. gflow_cli-0.5.0a1/src/gflow_cli/api/transports/experimental/sapisidhash.py +301 -0
  36. gflow_cli-0.5.0a1/src/gflow_cli/api/transports/ui_automation.py +611 -0
  37. gflow_cli-0.5.0a1/src/gflow_cli/browser_manager.py +633 -0
  38. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/cli.py +2 -0
  39. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/cli_image.py +49 -4
  40. gflow_cli-0.5.0a1/src/gflow_cli/cli_run.py +466 -0
  41. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/config.py +12 -0
  42. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/errors.py +49 -0
  43. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tasks/lessons.md +79 -0
  44. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/api/test_client.py +138 -0
  45. gflow_cli-0.5.0a1/tests/api/test_client_image.py +827 -0
  46. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/api/test_image.py +19 -10
  47. gflow_cli-0.5.0a1/tests/api/transports/test_base.py +41 -0
  48. gflow_cli-0.5.0a1/tests/api/transports/test_bearer.py +443 -0
  49. gflow_cli-0.5.0a1/tests/api/transports/test_common.py +203 -0
  50. gflow_cli-0.5.0a1/tests/api/transports/test_evaluate_fetch.py +463 -0
  51. gflow_cli-0.5.0a1/tests/api/transports/test_factory.py +60 -0
  52. gflow_cli-0.5.0a1/tests/api/transports/test_fingerprint.py +118 -0
  53. gflow_cli-0.5.0a1/tests/api/transports/test_sapisidhash.py +404 -0
  54. gflow_cli-0.5.0a1/tests/api/transports/test_ui_automation.py +996 -0
  55. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/cli/test_cli_image.py +119 -0
  56. gflow_cli-0.5.0a1/tests/cli/test_cli_run.py +421 -0
  57. gflow_cli-0.5.0a1/tests/e2e/__init__.py +0 -0
  58. gflow_cli-0.5.0a1/tests/e2e/test_transports_e2e.py +317 -0
  59. gflow_cli-0.5.0a1/tests/features/__init__.py +0 -0
  60. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/features/test_image_steps.py +3 -1
  61. gflow_cli-0.5.0a1/tests/smoke/__init__.py +0 -0
  62. gflow_cli-0.5.0a1/tests/smoke/test_real_flow.py +88 -0
  63. gflow_cli-0.5.0a1/tests/test_browser_manager.py +1543 -0
  64. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/test_errors.py +28 -0
  65. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/test_smoke.py +1 -1
  66. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/uv.lock +7 -1
  67. gflow_cli-0.4.0a2/tests/api/test_client_image.py +0 -799
  68. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/.claude/README.md +0 -0
  69. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/.env.template +0 -0
  70. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/.gitattributes +0 -0
  71. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/CLAUDE.md +0 -0
  72. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/CONTRIBUTING.md +0 -0
  73. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/DISCLAIMER.md +0 -0
  74. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/KNOWN_ISSUES.md +0 -0
  75. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/LICENSE +0 -0
  76. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/PLAN.md +0 -0
  77. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/docs/ARCHITECTURE.md +0 -0
  78. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/docs/CONFIGURATION.md +0 -0
  79. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/docs/USER_GUIDE.md +0 -0
  80. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/docs/superpowers/plans/2026-05-09-image-mvp-orchestration.md +0 -0
  81. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/docs/superpowers/plans/2026-05-09-image-mvp.md +0 -0
  82. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/docs/superpowers/plans/2026-05-09-video-mvp-orchestration.md +0 -0
  83. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/docs/superpowers/plans/2026-05-09-video-mvp.md +0 -0
  84. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/docs/superpowers/plans/2026-05-10-phase-4-hardening-orchestration.md +0 -0
  85. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/docs/superpowers/plans/2026-05-10-phase-4-hardening.md +0 -0
  86. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/docs/superpowers/specs/2026-05-10-phase-4-hardening-design.md +0 -0
  87. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/samples/README.md +0 -0
  88. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/samples/captured/01_upload_image.json +0 -0
  89. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/samples/captured/02_batchAsyncGenerateVideoText.json +0 -0
  90. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
  91. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/samples/captured/04_archive_workflow.json +0 -0
  92. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/samples/captured/05_createProject.json +0 -0
  93. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/samples/captured/06_batchGenerateImages.json +0 -0
  94. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/samples/captured/07_batchGenerateImages_seeded.json +0 -0
  95. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/scripts/smoke_e2e.py +0 -0
  96. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/scripts/smoke_image.py +0 -0
  97. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/skills/README.md +0 -0
  98. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/skills/gflow-cli/SKILL.md +0 -0
  99. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/__main__.py +0 -0
  100. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/_cli_helpers.py +0 -0
  101. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/api/__init__.py +0 -0
  102. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/api/_retry.py +0 -0
  103. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/api/dto.py +0 -0
  104. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/api/recaptcha.py +0 -0
  105. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/api/routes.py +0 -0
  106. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/api/video.py +0 -0
  107. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/auth.py +0 -0
  108. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/cli_video.py +0 -0
  109. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/manifest.py +0 -0
  110. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/observability.py +0 -0
  111. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/paths.py +0 -0
  112. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/src/gflow_cli/profile_store.py +0 -0
  113. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/__init__.py +0 -0
  114. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/api/__init__.py +0 -0
  115. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/api/test_client_generate_video.py +0 -0
  116. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/api/test_concurrency.py +0 -0
  117. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/api/test_dto.py +0 -0
  118. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/api/test_image_dto.py +0 -0
  119. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/api/test_recaptcha.py +0 -0
  120. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/api/test_retry.py +0 -0
  121. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/api/test_routes.py +0 -0
  122. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/api/test_video.py +0 -0
  123. {gflow_cli-0.4.0a2/tests/cli → gflow_cli-0.5.0a1/tests/api/transports}/__init__.py +0 -0
  124. {gflow_cli-0.4.0a2/tests/features → gflow_cli-0.5.0a1/tests/cli}/__init__.py +0 -0
  125. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/cli/test_error_handling.py +0 -0
  126. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/cli/test_helpers.py +0 -0
  127. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/conftest.py +0 -0
  128. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/features/auth.feature +0 -0
  129. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/features/conftest.py +0 -0
  130. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/features/image.feature +0 -0
  131. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/features/test_auth_steps.py +0 -0
  132. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/features/test_step_collision_guard.py +0 -0
  133. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/features/test_video_steps.py +0 -0
  134. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/features/video.feature +0 -0
  135. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/test_auth.py +0 -0
  136. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/test_cli_video.py +0 -0
  137. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/test_config.py +0 -0
  138. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/test_manifest.py +0 -0
  139. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/test_observability.py +0 -0
  140. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/test_paths.py +0 -0
  141. {gflow_cli-0.4.0a2 → gflow_cli-0.5.0a1}/tests/test_profile_store.py +0 -0
@@ -9,8 +9,8 @@ You are about to release a new version of `gflow-cli`. Follow this sequence verb
9
9
  ## Inputs
10
10
 
11
11
  Ask the user (if not already provided):
12
- 1. **Version** — the new SemVer (e.g. `0.2.0`, `0.2.0a1`, `1.0.0-rc1`). If they don't know, look at the latest entry in `CHANGELOG.md` `[Unreleased]` and propose the next bump (PATCH for fixes only, MINOR for new features, MAJOR for breaks).
13
- 2. **Pre-release?** — `0.x.y` is alpha by definition. Only the user can say if a `0.x.y-rc1` should ship.
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`) for Python package releases. If they don't know, look at the latest entry in `CHANGELOG.md` `[Unreleased]` and propose the next bump (PATCH for fixes only, MINOR for new features, MAJOR for breaks).
13
+ 2. **Pre-release?** — prerelease versions such as `0.4.0a3` should stay marked as GitHub prereleases. Only the user can say when a release line is ready for the stable tag, such as `0.4.0`.
14
14
 
15
15
  ## Sequence
16
16
 
@@ -41,7 +41,17 @@ Ask the user (if not already provided):
41
41
  version = "<NEW_VERSION>"
42
42
  ```
43
43
 
44
- 5. **Update `CHANGELOG.md`:**
44
+ 5. **Bump package version** in `src/gflow_cli/__init__.py`:
45
+ ```python
46
+ __version__ = "<NEW_VERSION>"
47
+ ```
48
+
49
+ 6. **Update version assertion tests** if present:
50
+ ```bash
51
+ rg -n "__version__|<OLD_VERSION>|version assertion" tests src pyproject.toml
52
+ ```
53
+
54
+ 7. **Update `CHANGELOG.md`:**
45
55
  - Move all entries under `## [Unreleased]` to a new `## [<NEW_VERSION>] — YYYY-MM-DD` section.
46
56
  - Leave `## [Unreleased]` empty.
47
57
  - Update the link footer:
@@ -50,24 +60,24 @@ Ask the user (if not already provided):
50
60
  [<NEW_VERSION>]: https://github.com/ffroliva/gflow-cli/releases/tag/v<NEW_VERSION>
51
61
  ```
52
62
 
53
- 6. **Commit the release prep.**
63
+ 8. **Commit the release prep.**
54
64
  ```bash
55
- git add pyproject.toml CHANGELOG.md
56
- git commit -m "release: v<NEW_VERSION>"
65
+ git add pyproject.toml src/gflow_cli/__init__.py CHANGELOG.md tests
66
+ git commit -m "chore(release): v<NEW_VERSION>"
57
67
  ```
58
68
 
59
- 7. **Tag.** Pre-release tags include `-rc*` / `-alpha*` / `-beta*`:
69
+ 9. **Tag.** PEP 440 prerelease tags include `aN` / `bN` / `rcN`:
60
70
  ```bash
61
71
  git tag -a v<NEW_VERSION> -m "v<NEW_VERSION>"
62
72
  ```
63
73
 
64
- 8. **Push commit + tag.**
74
+ 10. **Push commit + tag.**
65
75
  ```bash
66
76
  git push origin main
67
77
  git push origin v<NEW_VERSION>
68
78
  ```
69
79
 
70
- 9. **Report.** Tell the user:
80
+ 11. **Report.** Tell the user:
71
81
  - The pushed tag triggers `.github/workflows/release.yml`.
72
82
  - Watch <https://github.com/ffroliva/gflow-cli/actions> for the release workflow.
73
83
  - On success: PyPI publish + GitHub Release with auto-generated notes.
@@ -82,5 +92,6 @@ Ask the user (if not already provided):
82
92
 
83
93
  ## See also
84
94
 
85
- - [README § Releases](../../README.md#releases) — full release policy & cadence
95
+ - [RELEASE.md](../../RELEASE.md) — full release protocol, prerelease policy, and checklist
96
+ - [README § Releases](../../README.md#releases) — short release policy & cadence
86
97
  - [PLAN § Phase 5](../../PLAN.md#phase-5--public-alpha-release-on-pypi) — first-release exit criteria
@@ -32,4 +32,11 @@ jobs:
32
32
  run: uv run pyright src
33
33
 
34
34
  - name: Test (smoke only)
35
- run: uv run pytest -q
35
+ # e2e tests (tests/e2e/) require a logged-in `denon82` Chromium profile
36
+ # and live Flow auth — never runnable in CI. They self-mark with
37
+ # `pytestmark = pytest.mark.e2e` (file-level) and are opt-in via
38
+ # `-m e2e` per their module docstring. `live` marker is reserved for
39
+ # `GFLOW_LIVE=1` tests that hit the real Flow API. Both are excluded
40
+ # from the default smoke run; `tests/smoke/test_real_flow.py` already
41
+ # self-skips via `pytest.mark.skipif(GFLOW_E2E != "1")`.
42
+ run: uv run pytest -q -m "not e2e and not live"
@@ -50,4 +50,8 @@ jobs:
50
50
  with:
51
51
  generate_release_notes: true
52
52
  files: dist/*
53
- prerelease: ${{ contains(github.ref_name, '-') }}
53
+ # Pre-release detection covers both conventions:
54
+ # - semver suffixes: v1.2.3-alpha1, v1.2.3-rc1, v1.2.3-beta1 (any '-' qualifies)
55
+ # - PEP 440 suffixes: v1.2.3a1, v1.2.3b1, v1.2.3rc1 (any 'a' / 'b' / 'rc')
56
+ # Stable tags like v1.2.3 contain none of these substrings.
57
+ prerelease: ${{ contains(github.ref_name, '-') || contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc') }}
@@ -48,6 +48,13 @@ tmp/
48
48
  !tests/fixtures/**/*.png
49
49
  samples/*.captured.json # sandbox-recorded API exchanges may contain PII
50
50
 
51
+ # Live Flow traffic captures — NEVER commit (contain real Bearer tokens / API keys).
52
+ # Diagnostic scripts MUST default-write here, NOT to samples/captured/.
53
+ # Sanitised reference samples (no secrets) can still live under samples/captured/.
54
+ tmp/captured/
55
+ samples/captured/flow_outgoing_*.jsonl
56
+ samples/captured/flow_outgoing_*.json
57
+
51
58
  # Claude Code worktrees and lock files
52
59
  .claude/worktrees/
53
60
  .claude/scheduled_tasks.lock
@@ -0,0 +1,38 @@
1
+ ---
2
+ created: 2026-05-11T11:34:56.295Z
3
+ title: Add project logo and docs site promotion plan
4
+ area: docs
5
+ files:
6
+ - README.md:18
7
+ - README.md:365
8
+ - RELEASE.md:1
9
+ - docs/INDEX.md:10
10
+ ---
11
+
12
+ ## Problem
13
+
14
+ The project is now public on GitHub and PyPI and has enough release/process
15
+ surface to benefit from a more polished presentation. The README was cleaned up
16
+ with working badges and a public `RELEASE.md`, but the next promotion step is
17
+ still undecided: whether to add a logo/social preview, whether to create a
18
+ GitHub Pages documentation site, and which static-docs stack to use.
19
+
20
+ Jekyll is available on GitHub Pages, but for this Python CLI project the better
21
+ default is likely MkDocs Material: it fits Markdown-heavy CLI docs, has search
22
+ and navigation, and can publish to GitHub Pages cleanly. This should wait until
23
+ after the current prerelease E2E validation, because the real launch gate is
24
+ runtime confidence, not site polish.
25
+
26
+ ## Solution
27
+
28
+ After E2E validation, decide a small promotion package:
29
+
30
+ 1. Add a simple project logo and GitHub social preview image.
31
+ 2. Keep README as the landing page and make the first screen clear for users.
32
+ 3. If docs navigation grows cramped, add a MkDocs Material site published to
33
+ GitHub Pages.
34
+ 4. Avoid Jekyll unless the goal shifts toward a blog-style marketing site.
35
+ 5. Add the star-history chart only after the repo has enough activity for the
36
+ graph to render as useful signal rather than empty axes.
37
+ 6. Keep `RELEASE.md`, README release policy, and `.claude/commands/release.md`
38
+ in sync when the release process changes.
@@ -7,6 +7,96 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.5.0a1] — 2026-05-12
11
+
12
+ > **Pluggable image transport + JSON-described batch runs.** The image
13
+ > generation surface now ships a new default `ui_automation` transport —
14
+ > a Playwright-driven UI mimicry strategy validated end-to-end against
15
+ > real Flow on a Google AI Pro/Ultra profile. Three earlier HTTP
16
+ > transport strategies (`evaluate_fetch`, `bearer`, `sapisidhash`) move
17
+ > into a new `experimental/` subpackage; they remain importable for
18
+ > research but are hidden from the CLI by default. New top-level
19
+ > `gflow run --config <file>` command drives JSON-described sequential
20
+ > batches through one shared session.
21
+
22
+ ### Added
23
+
24
+ - **`UiAutomationTransport`** (`gflow_cli.api.transports.ui_automation`)
25
+ — new default transport. Drives the Flow editor on a logged-in
26
+ profile through a Playwright-managed persistent context (internal CDP
27
+ port; no externally-exposed debug port). Mirrors the validated
28
+ reference flow in `scripts/smoke_worker_style.py`.
29
+ - **`gflow run --config <file>`** — sequential JSON-described batch
30
+ command. Schema covers `profile`, `transport`, `output_dir`, and a
31
+ `prompts` list (1–50 entries) with per-prompt `text`,
32
+ `aspect_ratio`, `model`, `count`, and `output_filename`. Supports
33
+ `--continue-on-error` (default) and `--fail-fast` semantics; final
34
+ exit code is the max per-prompt exit code. ONE `FlowApiClient`
35
+ session wraps the whole loop so the browser/project persist across
36
+ prompts.
37
+ - **`examples/` directory** — three runnable scripts (`single_image_t2i.py`,
38
+ `batch_from_config.py`) + a copy-and-edit `sample_config.json` + an
39
+ index `examples/README.md`. All sanitised: no hardcoded profile
40
+ names, generic placeholder prompts, parameterised via `--profile` /
41
+ `$GFLOW_EXAMPLE_PROFILE`.
42
+ - **Opt-in real-Flow smoke test** at `tests/smoke/test_real_flow.py`,
43
+ gated by `GFLOW_E2E=1` + `GFLOW_E2E_PROFILE`. Runs the full
44
+ `UiAutomationTransport` flow against real Flow and asserts a
45
+ non-trivial PNG was written.
46
+ - **`EXPERIMENTAL_TRANSPORTS` constant** + **`transport_choices()`
47
+ helper** in `gflow_cli.api.transports`. The factory continues to
48
+ accept every registered key; the CLI `--transport` Choice list is
49
+ the gated surface (default = `ui_automation` only;
50
+ `GFLOW_CLI_EXPERIMENTAL_TRANSPORTS=1` expands to all four).
51
+ - **Download host allow-list** in `UiAutomationTransport._download`
52
+ (`googleusercontent.com`, `googleapis.com`, `google.com` suffix
53
+ match). `follow_redirects=False`. Prevents session cookies from
54
+ reaching a non-Google host through a malformed or compromised
55
+ `fifeUrl`.
56
+
57
+ ### Changed
58
+
59
+ - **Default `--transport` flag** flipped from `evaluate_fetch` to
60
+ `ui_automation` across `gflow image t2i`, `gflow image i2i`, and
61
+ `gflow image upload`. The change is transparent to existing scripts
62
+ unless they pinned `--transport evaluate_fetch` explicitly.
63
+ - **`evaluate_fetch` / `bearer` / `sapisidhash` strategies moved** to
64
+ `gflow_cli.api.transports.experimental.*`. Public registry keys
65
+ (the strings used by `make_transport()` and the
66
+ `GFLOW_CLI_TRANSPORT` env var) are unchanged. Import paths within
67
+ the package are the only user-visible delta.
68
+ - **Debug screenshots** captured by the strategy on `_enter_editor` /
69
+ `_send_prompt` failures are now **viewport-only**
70
+ (`full_page=False`) and emit a `WARNING` log line noting the file
71
+ may contain identifying information from the authenticated session.
72
+
73
+ ### Fixed
74
+
75
+ - Listener-attach race in `generate_images`. The earlier
76
+ `asyncio.create_task(_capture_batch_response(page))` scheduled the
77
+ listener registration AFTER the next event-loop tick; on a busy
78
+ loop the prompt click could fire before the listener attached,
79
+ causing the capture to time out. Refactored into a synchronous
80
+ `_attach_batch_response_listener(page)` + an `async
81
+ _await_captured(captured, ...)`. No more orphaned task on partial
82
+ failure.
83
+
84
+ ### Removed
85
+
86
+ - Dead `_extract_image_urls(response)` helper on
87
+ `UiAutomationTransport` and its five tests.
88
+ `generate_images` parses `body.media[]` directly through
89
+ `GeneratedImage.from_response_item`; the parallel helper was
90
+ unreachable.
91
+
92
+ ### Documentation
93
+
94
+ - `BrowserManager` module docstring updated to make explicit that the
95
+ module is retained for research / non-Flow use, not on the
96
+ v0.5.0a1 image-generation critical path. No behavior change.
97
+ - README "Project status" table updated with v0.5.0a1 row.
98
+ - `docs/USAGE.md` gains a `gflow run` section.
99
+
10
100
  ## [0.4.0a2] — 2026-05-11
11
101
 
12
102
  > **Documentation polish.** Same release surface as v0.4.0a1; this tag fixes
@@ -0,0 +1,68 @@
1
+ # gflow-cli Configuration Reference
2
+
3
+ ## Environment variables
4
+
5
+ | Env var | Default | Description |
6
+ |---|---|---|
7
+ | `GFLOW_CLI_HOME` | Platform data dir | Root directory for profiles and config. |
8
+ | `GFLOW_CLI_OUTPUT_DIR` | `~/Downloads/gflow-cli` | Where generated images and videos are saved. |
9
+ | `GFLOW_CLI_BROWSER` | `auto` | Browser mode. See **Browser mode** section below. |
10
+ | `CHROME_BINARY` | (autodetect) | Override Chrome binary path. Falls back to platform-standard locations. |
11
+ | `GFLOW_CLI_CONCURRENCY` | `4` | Maximum parallel API requests per batch. |
12
+ | `GFLOW_LIVE` | _(unset)_ | Set to `1` to enable live-API test markers (`@pytest.mark.live`). |
13
+
14
+ ---
15
+
16
+ ## Browser mode (D.2.3+)
17
+
18
+ | Env var | Default | Description |
19
+ |---|---|---|
20
+ | `GFLOW_CLI_BROWSER` | `auto` | `auto` attaches to running Chrome via CDP or spawns detached; `fresh` launches new Playwright Chromium per call (legacy); `cdp:<port>` attaches to explicit CDP endpoint. |
21
+ | `CHROME_BINARY` | (autodetect) | Override Chrome binary path. Falls back to platform-standard locations. |
22
+
23
+ ### When to use which
24
+
25
+ - **`auto`** (recommended): real Chrome fingerprint = highest reCAPTCHA risk score; persistent
26
+ across CLI invocations. First call spawns Chrome detached; subsequent calls attach via CDP.
27
+ - **`fresh`**: legacy single-shot Playwright Chromium. Use when you need a clean profile per call.
28
+ - **`cdp:<port>`**: connect to an already-running Chrome you spawned yourself
29
+ (e.g. with `--remote-debugging-port=9222`).
30
+
31
+ ### Chrome binary autodetection order
32
+
33
+ 1. `CHROME_BINARY` env var (checked first — always wins)
34
+ 2. `shutil.which("chrome")` / `shutil.which("google-chrome")` / `shutil.which("chromium")`
35
+ 3. Platform-standard paths:
36
+ - **Windows**: `C:\Program Files\Google\Chrome\Application\chrome.exe`,
37
+ `C:\Program Files (x86)\Google\Chrome\Application\chrome.exe`,
38
+ `%LOCALAPPDATA%\Google\Chrome\Application\chrome.exe`
39
+ - **macOS**: `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`
40
+ - **Linux**: `/usr/bin/google-chrome`, `/usr/bin/chromium`, `/usr/bin/chromium-browser`
41
+
42
+ If Chrome is not found, gflow-cli raises a `ConfigurationError` with an install hint.
43
+
44
+ ### CDP port range
45
+
46
+ By default gflow-cli uses CDP port `9222`. If that port is occupied by a non-gflow Chrome,
47
+ it probes `9222–9229` until a free port is found. The chosen port is persisted in
48
+ `<profile_dir>/.gflow-cdp.lock` so subsequent calls reuse the same port.
49
+
50
+ If all 8 ports are occupied, a `ConfigurationError` is raised.
51
+
52
+ ### Lockfile
53
+
54
+ `<profile_dir>/.gflow-cdp.lock` — JSON file containing `{pid, port, profile_name}`.
55
+ Written atomically (tmp + `os.link`, `O_CREAT|O_EXCL|O_NOFOLLOW`, mode `0o600`)
56
+ when Chrome is first spawned. Stale locks (PID no longer alive) are cleaned up
57
+ automatically on the next CLI invocation.
58
+
59
+ ### Security note — localhost CDP trust model
60
+
61
+ The Chrome DevTools Protocol endpoint (`http://localhost:<port>/json/version`)
62
+ is **not authenticated**. Any process on the same machine that can reach
63
+ `localhost:9222` can drive the browser. gflow-cli treats a port owner that
64
+ matches our lockfile as trusted; an unmanaged Chrome on the same port is
65
+ attached with a `attached_to_unmanaged_chrome=true` warning logged.
66
+
67
+ **Do not run gflow-cli on a shared multi-user machine** where untrusted users
68
+ have shell access. Use a dedicated user account or a VM per worker.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gflow-cli
3
- Version: 0.4.0a2
3
+ Version: 0.5.0a1
4
4
  Summary: Unofficial CLI for Google Flow — drive Veo image-to-video generations from the terminal.
5
5
  Project-URL: Homepage, https://github.com/ffroliva/gflow-cli
6
6
  Project-URL: Issues, https://github.com/ffroliva/gflow-cli/issues
@@ -69,7 +69,7 @@ Description-Content-Type: text/markdown
69
69
 
70
70
  > ⚠️ **Not affiliated with Google.** Reverse-engineered from public Flow web traffic. Endpoints can change at any time. See full [DISCLAIMER](DISCLAIMER.md) before use.
71
71
 
72
- 📚 **Docs:** [INDEX](docs/INDEX.md) · [User Guide](docs/USER_GUIDE.md) · [Architecture](docs/ARCHITECTURE.md) · [Authentication](docs/AUTHENTICATION.md) · [Configuration](docs/CONFIGURATION.md) · [Usage](docs/USAGE.md) · [Security](docs/SECURITY.md) · [Known issues](KNOWN_ISSUES.md) · [Plan](PLAN.md) · [Changelog](CHANGELOG.md)
72
+ 📚 **Docs:** [INDEX](docs/INDEX.md) · [User Guide](docs/USER_GUIDE.md) · [Architecture](docs/ARCHITECTURE.md) · [Authentication](docs/AUTHENTICATION.md) · [Configuration](docs/CONFIGURATION.md) · [Usage](docs/USAGE.md) · [Security](docs/SECURITY.md) · [Known issues](KNOWN_ISSUES.md) · [Release protocol](RELEASE.md) · [Plan](PLAN.md) · [Changelog](CHANGELOG.md)
73
73
  🤖 **For AI agents:** [CLAUDE.md](CLAUDE.md) · [`.claude/`](.claude/README.md)
74
74
 
75
75
  ---
@@ -108,7 +108,7 @@ Read the full [DISCLAIMER](DISCLAIMER.md) before deploying this in any productio
108
108
 
109
109
  ## Project status
110
110
 
111
- **v0.4.0a2 — alpha.** Video (T2V/I2V/batch), image (T2I/I2I/upload), and **batch concurrency, typed errors, retry/backoff, and structured logging** are functional end-to-end against a live Google AI Ultra/Pro Flow account.
111
+ **v0.5.0a1 — alpha.** Video (T2V/I2V/batch), image (T2I/I2I/upload), the new **`gflow run` JSON-batch command**, and the **`ui_automation` default transport** are functional end-to-end against a live Google AI Pro/Ultra Flow account. Three earlier HTTP transport strategies (`evaluate_fetch` / `bearer` / `sapisidhash`) move to an `experimental/` subpackage in this release; the production path is `ui_automation`.
112
112
 
113
113
  | Milestone | Status |
114
114
  |---|---|
@@ -122,7 +122,17 @@ Read the full [DISCLAIMER](DISCLAIMER.md) before deploying this in any productio
122
122
  | Typed errors (RFC 9457 Problem Details) + per-class exit codes 3–7 | ✅ done (v0.4.0a2) |
123
123
  | Retry / backoff + reCAPTCHA re-mint inside the retry loop | ✅ done (v0.4.0a2) |
124
124
  | Structured logs (`structlog`, JSON on pipe) | ✅ done (v0.4.0a2) |
125
- | Provider abstraction for official Veo 3.1 API | planned (v0.5+) |
125
+ | Pluggable image transport + `ui_automation` default strategy | done (v0.5.0a1) |
126
+ | `gflow run --config <file>` sequential JSON batches | ✅ done (v0.5.0a1) |
127
+ | `examples/` directory with runnable single-image + batch scripts | ✅ done (v0.5.0a1) |
128
+ | Provider abstraction for official Veo 3.1 API | ⏳ planned (v0.6+) |
129
+
130
+ ### What's new in v0.5.0a1
131
+
132
+ - `UiAutomationTransport` is now the default image-generation strategy — Playwright-driven UI mimicry against the Flow editor on a logged-in Pro/Ultra profile (no externally-exposed CDP debug port).
133
+ - New top-level `gflow run --config <file>` command for JSON-described sequential batches (1–50 prompts per file, `--continue-on-error` / `--fail-fast` modes). See [`docs/USAGE.md`](docs/USAGE.md#gflow-run) for the schema.
134
+ - Three runnable example scripts shipped under [`examples/`](examples/README.md) — copy and edit for your own pipelines.
135
+ - See the full [CHANGELOG](CHANGELOG.md#0501) for the security follow-ups (download host allow-list, viewport-only debug screenshots) and the listener-attach race fix.
126
136
 
127
137
  ---
128
138
 
@@ -376,17 +386,20 @@ Each `Provider` method has a corresponding test file under `tests/`. New routes
376
386
 
377
387
  1. Update [`CHANGELOG.md`](CHANGELOG.md) with the version's changes (Keep-a-Changelog format).
378
388
  2. Bump `version` in `pyproject.toml`.
379
- 3. Tag the commit:
389
+ 3. Bump `__version__` in `src/gflow_cli/__init__.py`.
390
+ 4. Tag the commit:
380
391
  ```bash
381
- git tag vX.Y.Z # or vX.Y.ZaN for an alpha
382
- git push origin vX.Y.Z
392
+ git tag v<version> # for example, v0.4.0 or v0.4.0a3
393
+ git push origin v<version>
383
394
  ```
384
- 4. The [`release.yml`](.github/workflows/release.yml) GitHub Action runs:
395
+ 5. The [`release.yml`](.github/workflows/release.yml) GitHub Action runs:
385
396
  - Builds the wheel + sdist with `uv build`
386
397
  - Publishes to PyPI via [Trusted Publishing](https://docs.pypi.org/trusted-publishers/) — no API tokens stored
387
398
  - Creates a GitHub Release with the changelog excerpt + built artifacts attached
388
399
 
389
- Pre-release tags (`v*.*.*-rc*`, `v*.*.*-alpha*`, `v*.*.*-beta*`) auto-flag as pre-releases on GitHub. Install with `pip install --pre gflow-cli` or `uvx --from "gflow-cli==0.4.0a2" gflow`.
400
+ PEP 440 prerelease tags (`vX.Y.ZaN`, `vX.Y.ZbN`, `vX.Y.ZrcN`) and hyphenated prerelease tags (`vX.Y.Z-alphaN`, `vX.Y.Z-betaN`, `vX.Y.Z-rcN`) auto-flag as prereleases on GitHub. Stable tags such as `v0.4.0` become full GitHub Releases. See [RELEASE.md](RELEASE.md) for the checklist and the prerelease/full-release policy.
401
+
402
+ Install prereleases explicitly with `pip install --pre gflow-cli` or `uvx --from "gflow-cli==0.4.0a2" gflow`.
390
403
 
391
404
  ---
392
405
 
@@ -422,6 +435,5 @@ Note that the **Google service** this tool talks to has its own terms (Google La
422
435
  [![GitHub last commit](https://img.shields.io/github/last-commit/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli/commits/main)
423
436
  [![GitHub repo size](https://img.shields.io/github/repo-size/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli)
424
437
  [![PyPI downloads](https://img.shields.io/pypi/dm/gflow-cli.svg)](https://pypi.org/project/gflow-cli/)
425
- [![PyPI total downloads](https://img.shields.io/pypi/dt/gflow-cli.svg)](https://pypi.org/project/gflow-cli/)
426
438
 
427
439
  If `gflow-cli` saves you time, please ⭐ the repo — it's the cheapest way to support the project.
@@ -15,7 +15,7 @@
15
15
 
16
16
  > ⚠️ **Not affiliated with Google.** Reverse-engineered from public Flow web traffic. Endpoints can change at any time. See full [DISCLAIMER](DISCLAIMER.md) before use.
17
17
 
18
- 📚 **Docs:** [INDEX](docs/INDEX.md) · [User Guide](docs/USER_GUIDE.md) · [Architecture](docs/ARCHITECTURE.md) · [Authentication](docs/AUTHENTICATION.md) · [Configuration](docs/CONFIGURATION.md) · [Usage](docs/USAGE.md) · [Security](docs/SECURITY.md) · [Known issues](KNOWN_ISSUES.md) · [Plan](PLAN.md) · [Changelog](CHANGELOG.md)
18
+ 📚 **Docs:** [INDEX](docs/INDEX.md) · [User Guide](docs/USER_GUIDE.md) · [Architecture](docs/ARCHITECTURE.md) · [Authentication](docs/AUTHENTICATION.md) · [Configuration](docs/CONFIGURATION.md) · [Usage](docs/USAGE.md) · [Security](docs/SECURITY.md) · [Known issues](KNOWN_ISSUES.md) · [Release protocol](RELEASE.md) · [Plan](PLAN.md) · [Changelog](CHANGELOG.md)
19
19
  🤖 **For AI agents:** [CLAUDE.md](CLAUDE.md) · [`.claude/`](.claude/README.md)
20
20
 
21
21
  ---
@@ -54,7 +54,7 @@ Read the full [DISCLAIMER](DISCLAIMER.md) before deploying this in any productio
54
54
 
55
55
  ## Project status
56
56
 
57
- **v0.4.0a2 — alpha.** Video (T2V/I2V/batch), image (T2I/I2I/upload), and **batch concurrency, typed errors, retry/backoff, and structured logging** are functional end-to-end against a live Google AI Ultra/Pro Flow account.
57
+ **v0.5.0a1 — alpha.** Video (T2V/I2V/batch), image (T2I/I2I/upload), the new **`gflow run` JSON-batch command**, and the **`ui_automation` default transport** are functional end-to-end against a live Google AI Pro/Ultra Flow account. Three earlier HTTP transport strategies (`evaluate_fetch` / `bearer` / `sapisidhash`) move to an `experimental/` subpackage in this release; the production path is `ui_automation`.
58
58
 
59
59
  | Milestone | Status |
60
60
  |---|---|
@@ -68,7 +68,17 @@ Read the full [DISCLAIMER](DISCLAIMER.md) before deploying this in any productio
68
68
  | Typed errors (RFC 9457 Problem Details) + per-class exit codes 3–7 | ✅ done (v0.4.0a2) |
69
69
  | Retry / backoff + reCAPTCHA re-mint inside the retry loop | ✅ done (v0.4.0a2) |
70
70
  | Structured logs (`structlog`, JSON on pipe) | ✅ done (v0.4.0a2) |
71
- | Provider abstraction for official Veo 3.1 API | planned (v0.5+) |
71
+ | Pluggable image transport + `ui_automation` default strategy | done (v0.5.0a1) |
72
+ | `gflow run --config <file>` sequential JSON batches | ✅ done (v0.5.0a1) |
73
+ | `examples/` directory with runnable single-image + batch scripts | ✅ done (v0.5.0a1) |
74
+ | Provider abstraction for official Veo 3.1 API | ⏳ planned (v0.6+) |
75
+
76
+ ### What's new in v0.5.0a1
77
+
78
+ - `UiAutomationTransport` is now the default image-generation strategy — Playwright-driven UI mimicry against the Flow editor on a logged-in Pro/Ultra profile (no externally-exposed CDP debug port).
79
+ - New top-level `gflow run --config <file>` command for JSON-described sequential batches (1–50 prompts per file, `--continue-on-error` / `--fail-fast` modes). See [`docs/USAGE.md`](docs/USAGE.md#gflow-run) for the schema.
80
+ - Three runnable example scripts shipped under [`examples/`](examples/README.md) — copy and edit for your own pipelines.
81
+ - See the full [CHANGELOG](CHANGELOG.md#0501) for the security follow-ups (download host allow-list, viewport-only debug screenshots) and the listener-attach race fix.
72
82
 
73
83
  ---
74
84
 
@@ -322,17 +332,20 @@ Each `Provider` method has a corresponding test file under `tests/`. New routes
322
332
 
323
333
  1. Update [`CHANGELOG.md`](CHANGELOG.md) with the version's changes (Keep-a-Changelog format).
324
334
  2. Bump `version` in `pyproject.toml`.
325
- 3. Tag the commit:
335
+ 3. Bump `__version__` in `src/gflow_cli/__init__.py`.
336
+ 4. Tag the commit:
326
337
  ```bash
327
- git tag vX.Y.Z # or vX.Y.ZaN for an alpha
328
- git push origin vX.Y.Z
338
+ git tag v<version> # for example, v0.4.0 or v0.4.0a3
339
+ git push origin v<version>
329
340
  ```
330
- 4. The [`release.yml`](.github/workflows/release.yml) GitHub Action runs:
341
+ 5. The [`release.yml`](.github/workflows/release.yml) GitHub Action runs:
331
342
  - Builds the wheel + sdist with `uv build`
332
343
  - Publishes to PyPI via [Trusted Publishing](https://docs.pypi.org/trusted-publishers/) — no API tokens stored
333
344
  - Creates a GitHub Release with the changelog excerpt + built artifacts attached
334
345
 
335
- Pre-release tags (`v*.*.*-rc*`, `v*.*.*-alpha*`, `v*.*.*-beta*`) auto-flag as pre-releases on GitHub. Install with `pip install --pre gflow-cli` or `uvx --from "gflow-cli==0.4.0a2" gflow`.
346
+ PEP 440 prerelease tags (`vX.Y.ZaN`, `vX.Y.ZbN`, `vX.Y.ZrcN`) and hyphenated prerelease tags (`vX.Y.Z-alphaN`, `vX.Y.Z-betaN`, `vX.Y.Z-rcN`) auto-flag as prereleases on GitHub. Stable tags such as `v0.4.0` become full GitHub Releases. See [RELEASE.md](RELEASE.md) for the checklist and the prerelease/full-release policy.
347
+
348
+ Install prereleases explicitly with `pip install --pre gflow-cli` or `uvx --from "gflow-cli==0.4.0a2" gflow`.
336
349
 
337
350
  ---
338
351
 
@@ -368,6 +381,5 @@ Note that the **Google service** this tool talks to has its own terms (Google La
368
381
  [![GitHub last commit](https://img.shields.io/github/last-commit/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli/commits/main)
369
382
  [![GitHub repo size](https://img.shields.io/github/repo-size/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli)
370
383
  [![PyPI downloads](https://img.shields.io/pypi/dm/gflow-cli.svg)](https://pypi.org/project/gflow-cli/)
371
- [![PyPI total downloads](https://img.shields.io/pypi/dt/gflow-cli.svg)](https://pypi.org/project/gflow-cli/)
372
384
 
373
385
  If `gflow-cli` saves you time, please ⭐ the repo — it's the cheapest way to support the project.
@@ -0,0 +1,97 @@
1
+ # Release Protocol
2
+
3
+ This project publishes Python distributions to PyPI and GitHub Releases from
4
+ Git tags. The release workflow is `.github/workflows/release.yml`.
5
+
6
+ ## Current Policy
7
+
8
+ - `0.x` versions are alpha-quality releases: useful for real testing, but APIs
9
+ may change before `1.0.0`.
10
+ - PEP 440 prerelease tags use the form `vX.Y.ZaN`, `vX.Y.ZbN`, or `vX.Y.ZrcN`.
11
+ Example: `v0.4.0a2`.
12
+ - Stable tags use the form `vX.Y.Z`. Example: `v0.4.0`.
13
+ - Never rewrite a pushed release tag. If a release is wrong, ship the next
14
+ version with a fix.
15
+
16
+ ## What The Workflow Does
17
+
18
+ When a tag matching `v*.*.*` is pushed, GitHub Actions:
19
+
20
+ 1. Verifies the tag matches `pyproject.toml` exactly after stripping the
21
+ leading `v`.
22
+ 2. Builds the wheel and source distribution with `uv build`.
23
+ 3. Publishes to PyPI through Trusted Publishing.
24
+ 4. Creates a GitHub Release and attaches the built artifacts.
25
+ 5. Marks tags containing PEP 440 alpha, beta, or release-candidate markers as
26
+ GitHub prereleases.
27
+
28
+ ## Prerelease Versus Full Release
29
+
30
+ Use a prerelease while validating behavior with end-to-end tests:
31
+
32
+ ```bash
33
+ 0.4.0a1
34
+ 0.4.0a2
35
+ 0.4.0rc1
36
+ ```
37
+
38
+ Use a full release only when the same release line is ready for general use:
39
+
40
+ ```bash
41
+ 0.4.0
42
+ ```
43
+
44
+ PyPI treats `0.4.0a2` as a prerelease version. Users can install it explicitly:
45
+
46
+ ```bash
47
+ uvx --from "gflow-cli==0.4.0a2" gflow --help
48
+ python -m pip install --pre gflow-cli
49
+ ```
50
+
51
+ ## Release Checklist
52
+
53
+ 1. Confirm the working tree is clean:
54
+ ```bash
55
+ git status --short
56
+ ```
57
+ 2. Confirm `main` is current:
58
+ ```bash
59
+ git fetch origin
60
+ git branch --show-current
61
+ git rev-list HEAD..origin/main
62
+ ```
63
+ 3. Run quality gates:
64
+ ```bash
65
+ uv run ruff check src tests
66
+ uv run ruff format --check src tests
67
+ uv run pyright src
68
+ uv run pytest -q
69
+ ```
70
+ 4. Update the version in:
71
+ - `pyproject.toml`
72
+ - `src/gflow_cli/__init__.py`
73
+ - any tests that assert the package version
74
+ 5. Move user-visible changes from `CHANGELOG.md` `[Unreleased]` into a dated
75
+ release section.
76
+ 6. Commit the release prep:
77
+ ```bash
78
+ git add pyproject.toml src/gflow_cli/__init__.py CHANGELOG.md tests
79
+ git commit -m "chore(release): vX.Y.Z"
80
+ ```
81
+ 7. Tag and push:
82
+ ```bash
83
+ git tag -a vX.Y.Z -m "vX.Y.Z"
84
+ git push origin main
85
+ git push origin vX.Y.Z
86
+ ```
87
+ 8. Watch the release workflow:
88
+ <https://github.com/ffroliva/gflow-cli/actions/workflows/release.yml>
89
+ 9. Confirm the new version appears on:
90
+ - <https://pypi.org/project/gflow-cli/>
91
+ - <https://github.com/ffroliva/gflow-cli/releases>
92
+
93
+ ## Known Historical Quirk
94
+
95
+ Older alpha tags (`v0.2.0a1`, `v0.3.0a1`) were created as normal GitHub
96
+ Releases because the workflow only detected hyphenated prerelease names. The
97
+ workflow now recognizes PEP 440 alpha, beta, and release-candidate tags.
@@ -230,7 +230,7 @@ Re-running `auth login` refreshes the cookies in place — no other state is los
230
230
  |---|---|
231
231
  | Session file leaked to a public repo | `.gitignore` excludes profile dirs at every layer. Recommended belt-and-braces: keep the gflow-cli home outside the repo (default location via `platformdirs` already does this) and run `git status` before any commit. Automatic in-repo detection is on the backlog (not yet scheduled). |
232
232
  | Multi-user shared machine | Profiles live under each user's home dir; OS file permissions (`0700` on POSIX, ACL on Windows) prevent cross-user reads by default. |
233
- | `gflow-cli` itself becomes malicious | The package is open-source under MIT; pin a version (`uv tool install gflow-cli==0.4.0a2`) and review release diffs before upgrading. |
233
+ | `gflow-cli` itself becomes malicious | The package is open-source under MIT; pin a version (`uv tool install gflow-cli==0.5.0a1`) and review release diffs before upgrading. |
234
234
  | Stolen laptop | Anyone with disk access has your session. Use full-disk encryption (FileVault, BitLocker, LUKS). Consider a dedicated `--profile sandbox` for short-lived experiments. |
235
235
  | Sharing a profile between machines | Technically works (copy the profile dir), but Google may flag the device-fingerprint mismatch as suspicious. Re-login on the new machine instead. |
236
236
 
@@ -7,6 +7,7 @@ Welcome to the `gflow-cli` documentation. This index is the routing layer: it te
7
7
  | [README](../README.md) | Project overview, install, quick start | First time landing on the repo |
8
8
  | [CLAUDE.md](../CLAUDE.md) | Project memory hub for AI coding agents | First time an agent (Claude/Cursor/Codex/Gemini/Aider) opens the repo |
9
9
  | [PLAN.md](../PLAN.md) | Implementation plan (DDD / CQRS / phases / ADRs) | You want the architectural intent and roadmap |
10
+ | [RELEASE.md](../RELEASE.md) | Release checklist, prerelease policy, PyPI/GitHub publishing protocol | Cutting or auditing a release |
10
11
  | [CHANGELOG](../CHANGELOG.md) | Version-by-version user-visible changes | Upgrading or auditing what shipped |
11
12
  | [KNOWN_ISSUES](../KNOWN_ISSUES.md) | Open / mitigated / resolved issues with workarounds | Before opening a bug report; when something feels off |
12
13
  | [DISCLAIMER](../DISCLAIMER.md) | Legal scope, takedown policy, prohibited uses | Before deploying anywhere non-trivial |
@@ -31,6 +32,7 @@ Welcome to the `gflow-cli` documentation. This index is the routing layer: it te
31
32
  **"Exit code 4 (rate-limit) or 5 (content-policy) — how do I recover?"** → [USER_GUIDE § Journey 12](USER_GUIDE.md#journey-12--recovering-from-contentpolicyerror-or-ratelimiterror)
32
33
  **"How do I read the structured log (`error_raised` events)?"** → [USER_GUIDE § Journey 6](USER_GUIDE.md#journey-6--reading-structured-logs-jq-recipes)
33
34
  **"What exit code does shell branching see for each error class?"** → [USAGE § Exit codes](USAGE.md#exit-codes)
35
+ **"Is `v0.5.0a1` a prerelease, and how do I cut a full release?"** → [RELEASE § Prerelease Versus Full Release](../RELEASE.md#prerelease-versus-full-release)
34
36
  **"Where is my session stored?"** → [AUTHENTICATION § Session storage](AUTHENTICATION.md#session-storage)
35
37
  **"Where do generated files land?"** → [CONFIGURATION § Output paths](CONFIGURATION.md#output-paths)
36
38
  **"How do I run with multiple Google accounts?"** → [AUTHENTICATION § Multiple accounts](AUTHENTICATION.md#multiple-accounts)
@@ -50,7 +50,7 @@ For users on shared / multi-user / production-adjacent machines:
50
50
  - [ ] **Set `GFLOW_CLI_HOME` to a non-default path** if you want the session away from the standard `LOCALAPPDATA` / `~/.local/share` location for any reason (auditability, separate volumes).
51
51
  - [ ] **Use `--profile sandbox`** for short-lived experiments. Easy to delete (`rm -rf $GFLOW_CLI_HOME/profile_sandbox`) without disturbing your main profile.
52
52
  - [ ] **Rotate sessions monthly** by signing out of Google → re-running `gflow auth login`. Limits blast radius of an unnoticed session theft.
53
- - [ ] **Pin a gflow-cli version** in production (`uv tool install gflow-cli==0.4.0a2`) and review release diffs before upgrading.
53
+ - [ ] **Pin a gflow-cli version** in production (`uv tool install gflow-cli==0.5.0a1`) and review release diffs before upgrading.
54
54
  - [ ] **Keep the package up-to-date for security fixes.** Subscribe to GitHub Releases for `ffroliva/gflow-cli`.
55
55
  - [ ] **Scan your repo for accidentally-committed profiles** before pushing: `git ls-files | grep -E "profile_|cookies\.json|\.env$"`.
56
56