gflow-cli 0.15.0__tar.gz → 0.15.1__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 (400) hide show
  1. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/AGENTS.md +3 -1
  2. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/CHANGELOG.md +17 -1
  3. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/PKG-INFO +9 -9
  4. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/README.md +8 -8
  5. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/INDEX.md +6 -1
  6. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/pyproject.toml +1 -1
  7. gflow_cli-0.15.1/scripts/diag/README.md +29 -0
  8. gflow_cli-0.15.0/scripts/diag_capture_flow_traffic.py → gflow_cli-0.15.1/scripts/diag/capture_flow_traffic.py +1 -1
  9. gflow_cli-0.15.1/scripts/diag/memory_profile.py +235 -0
  10. gflow_cli-0.15.0/scripts/diag_recaptcha_mint.py → gflow_cli-0.15.1/scripts/diag/recaptcha_mint.py +1 -1
  11. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/__init__.py +1 -1
  12. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/client.py +1 -1
  13. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/transports/ui_automation.py +1 -0
  14. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/transports/ui_automation_video.py +9 -0
  15. gflow_cli-0.15.1/tests/api/test_client_launch_kwargs.py +77 -0
  16. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/transports/test_ui_automation_video.py +26 -1
  17. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/dev/test_recording_client.py +4 -1
  18. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/uv.lock +1 -1
  19. gflow_cli-0.15.0/tests/api/test_client_launch_kwargs.py +0 -35
  20. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.claude/README.md +0 -0
  21. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.claude/commands/gflow/active.md +0 -0
  22. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.claude/commands/gflow/branch-review.md +0 -0
  23. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.claude/commands/gflow/changelog.md +0 -0
  24. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.claude/commands/gflow/check.md +0 -0
  25. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.claude/commands/gflow/doc-review.md +0 -0
  26. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.claude/commands/gflow/known-issues.md +0 -0
  27. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.claude/commands/gflow/next.md +0 -0
  28. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.claude/commands/gflow/plan.md +0 -0
  29. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.claude/commands/gflow/pr-council-review.md +0 -0
  30. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.claude/commands/gflow/predict.md +0 -0
  31. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.claude/commands/gflow/release.md +0 -0
  32. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.claude/commands/gflow/scenario.md +0 -0
  33. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.claude/commands/gflow/status.md +0 -0
  34. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.continue-here.md +0 -0
  35. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.env.template +0 -0
  36. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.gitattributes +0 -0
  37. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.github/CODEOWNERS +0 -0
  38. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  39. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.github/copilot-instructions.md +0 -0
  40. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.github/dependabot.yml +0 -0
  41. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.github/workflows/ci.yml +0 -0
  42. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.github/workflows/external-pr-triage.yml +0 -0
  43. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.github/workflows/governance-advisory.yml +0 -0
  44. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.github/workflows/governance-benchmark.yml +0 -0
  45. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.github/workflows/release.yml +0 -0
  46. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.gitignore +0 -0
  47. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.gitleaks.toml +0 -0
  48. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.pre-commit-config.yaml +0 -0
  49. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/.secrets.baseline +0 -0
  50. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/CLAUDE.md +0 -0
  51. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/CONFIGURATION.md +0 -0
  52. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/CONTRIBUTING.md +0 -0
  53. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/DISCLAIMER.md +0 -0
  54. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/GEMINI.md +0 -0
  55. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/KNOWN_ISSUES.md +0 -0
  56. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/LICENSE +0 -0
  57. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/PLAN.md +0 -0
  58. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/PR162_MOVIE_CHARACTER_REVIEW.md +0 -0
  59. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/RELEASE.md +0 -0
  60. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/ROADMAP.md +0 -0
  61. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/conftest.py +0 -0
  62. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docker-compose.yml +0 -0
  63. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/AGENT_GUIDE.md +0 -0
  64. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/ARCHITECTURE.md +0 -0
  65. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/AUTHENTICATION.md +0 -0
  66. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/CHARACTER.md +0 -0
  67. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/CHARACTER_RECON.md +0 -0
  68. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/CONFIGURATION.md +0 -0
  69. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/DATA_LAYER.md +0 -0
  70. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/DEBUGGING.md +0 -0
  71. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/DEMOS.md +0 -0
  72. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/DEVELOPMENT.md +0 -0
  73. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/E2E_TESTING.md +0 -0
  74. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/EXTERNAL_STORAGE.md +0 -0
  75. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/GITHUB.md +0 -0
  76. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/GOVERNANCE_BENCHMARK.md +0 -0
  77. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/LIVE_VERIFICATION_data_layer.md +0 -0
  78. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/LIVE_VERIFICATION_image_batch.md +0 -0
  79. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/LIVE_VERIFICATION_v0.10.0.md +0 -0
  80. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/LIVE_VERIFICATION_v0.11.0.md +0 -0
  81. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/LIVE_VERIFICATION_v0.12.0.md +0 -0
  82. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/LIVE_VERIFICATION_v0.13.0.md +0 -0
  83. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/LIVE_VERIFICATION_v0.7.0.md +0 -0
  84. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/LIVE_VERIFICATION_v0.8.1.md +0 -0
  85. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/LIVE_VERIFICATION_v0.9.0.md +0 -0
  86. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/LIVE_VERIFICATION_v0.9.1.md +0 -0
  87. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/LIVE_VERIFICATION_video_download.md +0 -0
  88. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/MOVIE.md +0 -0
  89. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/PROJECT_STATUS.md +0 -0
  90. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/SECURITY.md +0 -0
  91. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/USAGE.md +0 -0
  92. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/USER_GUIDE.md +0 -0
  93. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/assets/demo-split-pf.gif +0 -0
  94. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/assets/example-run.gif +0 -0
  95. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/schemas/movie-handoff.schema.json +0 -0
  96. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/superpowers/2026-05-17-issue-15-handover.md +0 -0
  97. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/superpowers/character-scenario.md +0 -0
  98. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/superpowers/plans/2026-06-01-governance-enforcement-advisory/PLAN.md +0 -0
  99. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/superpowers/plans/2026-06-04-character-create-recording.md +0 -0
  100. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/superpowers/plans/2026-06-06-movie-p0-asyncio-hotfix.md +0 -0
  101. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/superpowers/plans/2026-06-06-movie-p1-composition-manifest.md +0 -0
  102. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/superpowers/plans/2026-06-06-movie-p2-native-identity-voice.md +0 -0
  103. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/superpowers/specs/2026-06-06-movie-consistency-design.md +0 -0
  104. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/docs/superpowers/verifications/2026-05-11-phase-4-stage-g.md +0 -0
  105. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/examples/README.md +0 -0
  106. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/examples/batch_from_config.py +0 -0
  107. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/examples/multi_prompt_t2i.py +0 -0
  108. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/examples/sample_config.json +0 -0
  109. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/examples/sample_prompts.txt +0 -0
  110. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/examples/single_image_t2i.py +0 -0
  111. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/examples/workflow_chain.py +0 -0
  112. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/llms.txt +0 -0
  113. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/samples/README.md +0 -0
  114. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/samples/captured/01_upload_image.json +0 -0
  115. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/samples/captured/02_batchAsyncGenerateVideoText.json +0 -0
  116. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
  117. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/samples/captured/04_archive_workflow.json +0 -0
  118. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/samples/captured/05_createProject.json +0 -0
  119. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/samples/captured/06_batchGenerateImages.json +0 -0
  120. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/samples/captured/07_batchGenerateImages_seeded.json +0 -0
  121. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/samples/captured/08_batchAsyncGenerateVideoStartAndEndImage.json +0 -0
  122. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/samples/captured/09_batchAsyncGenerateVideoReferenceImages.json +0 -0
  123. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/samples/captured/10_batchCheckAsyncVideoGenerationStatus_successful.json +0 -0
  124. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/samples/captured/11_batchCheckAsyncVideoGenerationStatus_failed.json +0 -0
  125. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/samples/captured/12_create_scene.json +0 -0
  126. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/samples/captured/13_sceneWorkflows_update.json +0 -0
  127. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/samples/captured/14_get_scene_workflows.json +0 -0
  128. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/samples/captured/15_commit_flowWorkflow.json +0 -0
  129. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/ci/check_doc_links.py +0 -0
  130. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/ci/check_materiality.py +0 -0
  131. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/ci/check_repo_hygiene.py +0 -0
  132. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/debug_editor.py +0 -0
  133. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/debug_gen_settings.py +0 -0
  134. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/debug_settings.py +0 -0
  135. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/_recording_client.py +0 -0
  136. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/_spike_common.py +0 -0
  137. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/active_plan.py +0 -0
  138. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/capture_i2v_frame_slots_dom.py +0 -0
  139. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/capture_i2v_intercept_submit.py +0 -0
  140. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/capture_i2v_model_select_repro.py +0 -0
  141. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/capture_i2v_post_bind_state.py +0 -0
  142. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/capture_image_add_media_dom.py +0 -0
  143. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/capture_locale_invariants.py +0 -0
  144. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/cdp_drive_and_probe.py +0 -0
  145. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/character_create_spike.py +0 -0
  146. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/character_create_spike_v2.py +0 -0
  147. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/dump_character_selectors.js +0 -0
  148. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/make_project.py +0 -0
  149. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/materiality_backtest.py +0 -0
  150. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/monitor_pr_38.py +0 -0
  151. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/patch_character.py +0 -0
  152. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/record_flow_capture.py +0 -0
  153. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/skillopt/README.md +0 -0
  154. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/skillopt/harness.py +0 -0
  155. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/skillopt/tasks.json +0 -0
  156. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/spike_char_editor_dom.py +0 -0
  157. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/spike_char_gen_capture.py +0 -0
  158. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/spike_movie_attach_payload.py +0 -0
  159. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/spike_movie_entity_recon.py +0 -0
  160. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/spike_movie_gen_capture.py +0 -0
  161. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/spike_movie_picker_select.py +0 -0
  162. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/spike_movie_voice_list.py +0 -0
  163. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/dev/spike_patch_entity.py +0 -0
  164. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/record_demo.ps1 +0 -0
  165. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/smoke_image.py +0 -0
  166. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/smoke_real_chrome_image.py +0 -0
  167. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/smoke_video_editor.py +0 -0
  168. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/smoke_worker_style.py +0 -0
  169. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/scripts/verify_chrome_auth_viability.py +0 -0
  170. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/skills/README.md +0 -0
  171. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/skills/gflow-cli/SKILL.md +0 -0
  172. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/skills/plan/SKILL.md +0 -0
  173. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/skills/pr-council-review/SKILL.md +0 -0
  174. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/skills/predict/SKILL.md +0 -0
  175. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/skills/scenario/SKILL.md +0 -0
  176. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/skills/status/SKILL.md +0 -0
  177. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/sonar-project.properties +0 -0
  178. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/__main__.py +0 -0
  179. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/_cli_helpers.py +0 -0
  180. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/__init__.py +0 -0
  181. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/_retry.py +0 -0
  182. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/_sapisidhash.py +0 -0
  183. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/character.py +0 -0
  184. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/dto.py +0 -0
  185. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/image.py +0 -0
  186. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/recaptcha.py +0 -0
  187. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/routes.py +0 -0
  188. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/scene.py +0 -0
  189. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/transports/__init__.py +0 -0
  190. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/transports/_common.py +0 -0
  191. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/transports/_fingerprint.py +0 -0
  192. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/transports/base.py +0 -0
  193. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/transports/experimental/__init__.py +0 -0
  194. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/transports/experimental/bearer.py +0 -0
  195. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/transports/experimental/evaluate_fetch.py +0 -0
  196. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/transports/experimental/sapisidhash.py +0 -0
  197. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/api/video.py +0 -0
  198. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/auth/__init__.py +0 -0
  199. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/auth/base.py +0 -0
  200. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/auth/factory.py +0 -0
  201. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/auth/internal_chromium.py +0 -0
  202. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/auth/real_chrome.py +0 -0
  203. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/auth/strategies.py +0 -0
  204. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/auth/verification.py +0 -0
  205. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/browser_manager.py +0 -0
  206. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/chain.py +0 -0
  207. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/chain_manifest.py +0 -0
  208. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/cli.py +0 -0
  209. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/cli_character.py +0 -0
  210. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/cli_data.py +0 -0
  211. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/cli_image.py +0 -0
  212. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/cli_models.py +0 -0
  213. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/cli_movie.py +0 -0
  214. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/cli_run.py +0 -0
  215. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/cli_scene.py +0 -0
  216. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/cli_video.py +0 -0
  217. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/composition.py +0 -0
  218. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/config.py +0 -0
  219. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/data/__init__.py +0 -0
  220. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/data/chain_repo.py +0 -0
  221. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/data/migrations/0001_initial.sql +0 -0
  222. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/data/migrations/0002_add_cloud_storage.sql +0 -0
  223. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/data/migrations/0003_add_scene_tables.sql +0 -0
  224. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/data/migrations/0004_add_scene_output_path.sql +0 -0
  225. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/data/migrations/0005_add_chain_links.sql +0 -0
  226. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/data/migrations/0006_add_operations_metadata.sql +0 -0
  227. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/data/migrations/__init__.py +0 -0
  228. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/data/models.py +0 -0
  229. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/data/queries.py +0 -0
  230. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/data/recorder.py +0 -0
  231. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/data/redaction.py +0 -0
  232. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/data/repository.py +0 -0
  233. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/data/store.py +0 -0
  234. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/errors.py +0 -0
  235. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/exceptions.py +0 -0
  236. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/image_batch.py +0 -0
  237. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/json_output.py +0 -0
  238. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/manifest.py +0 -0
  239. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/media.py +0 -0
  240. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/movie_manifest.py +0 -0
  241. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/observability.py +0 -0
  242. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/paths.py +0 -0
  243. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/profile_store.py +0 -0
  244. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/services/__init__.py +0 -0
  245. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/services/character_create.py +0 -0
  246. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/src/gflow_cli/storage.py +0 -0
  247. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tasks/lessons.md +0 -0
  248. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/test_assets/sample_batch.json +0 -0
  249. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/test_assets/sample_batch.tsv +0 -0
  250. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/test_assets/sample_batch_invalid.tsv +0 -0
  251. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/__init__.py +0 -0
  252. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/__init__.py +0 -0
  253. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/fixtures/character_gen_response.json +0 -0
  254. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/fixtures/patch_entity_response.json +0 -0
  255. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_aisandbox_auth_error.py +0 -0
  256. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_aisandbox_auth_headers.py +0 -0
  257. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_bearer_redaction.py +0 -0
  258. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_character.py +0 -0
  259. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_client.py +0 -0
  260. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_client_character.py +0 -0
  261. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_client_delete_characters.py +0 -0
  262. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_client_generate_character.py +0 -0
  263. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_client_image.py +0 -0
  264. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_client_patch_entity.py +0 -0
  265. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_client_scene.py +0 -0
  266. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_concurrency.py +0 -0
  267. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_dto.py +0 -0
  268. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_image.py +0 -0
  269. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_image_dto.py +0 -0
  270. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_post_json_aisandbox_auth.py +0 -0
  271. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_recaptcha.py +0 -0
  272. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_retry.py +0 -0
  273. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_routes.py +0 -0
  274. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_routes_character.py +0 -0
  275. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_routes_scene.py +0 -0
  276. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_sapisidhash_helper.py +0 -0
  277. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_scene_models.py +0 -0
  278. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_video.py +0 -0
  279. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/test_video_request.py +0 -0
  280. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/transports/__init__.py +0 -0
  281. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/transports/test_base.py +0 -0
  282. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/transports/test_bearer.py +0 -0
  283. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/transports/test_common.py +0 -0
  284. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/transports/test_evaluate_fetch.py +0 -0
  285. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/transports/test_factory.py +0 -0
  286. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/transports/test_fingerprint.py +0 -0
  287. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/transports/test_sapisidhash.py +0 -0
  288. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/transports/test_transport_timeout.py +0 -0
  289. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/transports/test_ui_automation.py +0 -0
  290. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/transports/test_ui_automation_batch.py +0 -0
  291. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/transports/test_ui_automation_image_mode.py +0 -0
  292. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/api/transports/test_ui_character_editor.py +0 -0
  293. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/auth/strategies/test_factory.py +0 -0
  294. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/auth/strategies/test_strategies.py +0 -0
  295. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/auth/test_verification.py +0 -0
  296. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/__init__.py +0 -0
  297. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/test_cli_auth_list.py +0 -0
  298. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/test_cli_character.py +0 -0
  299. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/test_cli_character_create.py +0 -0
  300. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/test_cli_data.py +0 -0
  301. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/test_cli_image.py +0 -0
  302. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/test_cli_image_seed_removed.py +0 -0
  303. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/test_cli_models.py +0 -0
  304. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/test_cli_movie.py +0 -0
  305. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/test_cli_run.py +0 -0
  306. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/test_cli_scene.py +0 -0
  307. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/test_cli_video.py +0 -0
  308. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/test_cli_video_chain.py +0 -0
  309. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/test_error_handling.py +0 -0
  310. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/test_helpers.py +0 -0
  311. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/test_movie_manifest.py +0 -0
  312. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/cli/test_t2i_multi_prompt.py +0 -0
  313. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/composition/test_character.py +0 -0
  314. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/composition/test_compose_prompt.py +0 -0
  315. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/composition/test_handoff.py +0 -0
  316. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/conftest.py +0 -0
  317. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/data/__init__.py +0 -0
  318. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/data/test_chain_repo.py +0 -0
  319. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/data/test_find_incomplete_character.py +0 -0
  320. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/data/test_models.py +0 -0
  321. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/data/test_packaging.py +0 -0
  322. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/data/test_recorder.py +0 -0
  323. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/data/test_recorder_character.py +0 -0
  324. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/data/test_redaction.py +0 -0
  325. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/data/test_repository.py +0 -0
  326. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/data/test_scene_persistence.py +0 -0
  327. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/data/test_settings_and_errors.py +0 -0
  328. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/data/test_store_migrations.py +0 -0
  329. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/dev/test_record_flow_capture.py +0 -0
  330. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/e2e/__init__.py +0 -0
  331. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/e2e/conftest.py +0 -0
  332. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/e2e/test_aisandbox_auth_live.py +0 -0
  333. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/e2e/test_auth_verification_e2e.py +0 -0
  334. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/e2e/test_chain_e2e.py +0 -0
  335. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/e2e/test_character_create_e2e.py +0 -0
  336. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/e2e/test_data_layer_e2e.py +0 -0
  337. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/e2e/test_i2v_flags_e2e.py +0 -0
  338. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/e2e/test_image_batch_e2e.py +0 -0
  339. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/e2e/test_image_i2i_ref_cap_e2e.py +0 -0
  340. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/e2e/test_json_output_e2e.py +0 -0
  341. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/e2e/test_locale_selectors_e2e.py +0 -0
  342. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/e2e/test_scene_compose_live.py +0 -0
  343. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/e2e/test_transports_e2e.py +0 -0
  344. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/e2e/test_video_r2v_ref_cap_e2e.py +0 -0
  345. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/e2e/test_video_t2v_e2e.py +0 -0
  346. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/features/__init__.py +0 -0
  347. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/features/auth.feature +0 -0
  348. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/features/auth_login.feature +0 -0
  349. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/features/character_create.feature +0 -0
  350. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/features/character_read.feature +0 -0
  351. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/features/conftest.py +0 -0
  352. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/features/image.feature +0 -0
  353. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/features/test_auth_login_steps.py +0 -0
  354. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/features/test_auth_steps.py +0 -0
  355. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/features/test_character_create_steps.py +0 -0
  356. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/features/test_character_read_steps.py +0 -0
  357. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/features/test_image_steps.py +0 -0
  358. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/features/test_step_collision_guard.py +0 -0
  359. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/features/test_video_chain_steps.py +0 -0
  360. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/features/video_chain.feature +0 -0
  361. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/fixtures/__init__.py +0 -0
  362. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/fixtures/seeded_catalog.py +0 -0
  363. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/image_batch/__init__.py +0 -0
  364. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/image_batch/test_image_manifest.py +0 -0
  365. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/image_batch/test_observability_events.py +0 -0
  366. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/integration/__init__.py +0 -0
  367. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/integration/conftest.py +0 -0
  368. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/integration/constants.py +0 -0
  369. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/integration/test_storage_gcs.py +0 -0
  370. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/integration/test_storage_s3.py +0 -0
  371. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/scripts/test_capture_locale_invariants.py +0 -0
  372. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/scripts/test_check_materiality.py +0 -0
  373. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/scripts/test_check_repo_hygiene.py +0 -0
  374. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/scripts/test_materiality_backtest.py +0 -0
  375. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/services/__init__.py +0 -0
  376. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/services/test_character_create_redaction.py +0 -0
  377. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/services/test_character_create_saga.py +0 -0
  378. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/services/test_character_gen_no_direct_post.py +0 -0
  379. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/smoke/__init__.py +0 -0
  380. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/smoke/test_profile_account_smoke.py +0 -0
  381. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/smoke/test_real_flow.py +0 -0
  382. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_auth.py +0 -0
  383. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_browser_manager.py +0 -0
  384. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_chain.py +0 -0
  385. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_chain_manifest.py +0 -0
  386. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_cli_data.py +0 -0
  387. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_config.py +0 -0
  388. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_conftest_isolation.py +0 -0
  389. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_data_queries.py +0 -0
  390. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_documentation_gate.py +0 -0
  391. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_errors.py +0 -0
  392. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_errors_403.py +0 -0
  393. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_json_output.py +0 -0
  394. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_manifest.py +0 -0
  395. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_marker_registry.py +0 -0
  396. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_media.py +0 -0
  397. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_observability.py +0 -0
  398. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_paths.py +0 -0
  399. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_profile_store.py +0 -0
  400. {gflow_cli-0.15.0 → gflow_cli-0.15.1}/tests/test_smoke.py +0 -0
@@ -76,10 +76,12 @@ The `skills/` directory ships installable agent skill docs in plain Markdown wit
76
76
  | `gflow-cli` | [`skills/gflow-cli/SKILL.md`](skills/gflow-cli/SKILL.md) | User wants to run any `gflow` command — auth, T2V, I2V, T2I, I2I, batch |
77
77
  | `predict` | [`skills/predict/SKILL.md`](skills/predict/SKILL.md) | Pre-implementation adversarial analysis before any high-stakes change |
78
78
  | `scenario` | [`skills/scenario/SKILL.md`](skills/scenario/SKILL.md) | Edge-case explorer after a predict GO/CAUTION |
79
+ | `plan` | [`skills/plan/SKILL.md`](skills/plan/SKILL.md) | Create a structured task-by-task implementation plan for a feature |
80
+ | `status` | [`skills/status/SKILL.md`](skills/status/SKILL.md) | Show current plan state, progress, and next unchecked task |
79
81
  | `pr-council-review` | [`skills/pr-council-review/SKILL.md`](skills/pr-council-review/SKILL.md) | Multi-dimensional PR council review |
80
82
 
81
83
  **Cursor / Aider / Codex / Gemini CLI:** paste or include the relevant `SKILL.md` in your system context.
82
- **Claude Code:** symlink `skills/gflow-cli` to `~/.claude/skills/gflow-cli` to register the skill; the `/gflow:` slash commands (in `.claude/commands/gflow/`) are auto-discovered from the project directory.
84
+ **Claude Code:** the `/gflow:` slash commands in `.claude/commands/gflow/` are auto-discovered when the project is open — no extra setup needed. To register a skill globally, copy the command file to `~/.claude/commands/`.
83
85
  **Custom agents:** fetch `skills/gflow-cli/SKILL.md` into your knowledge base before answering gflow questions.
84
86
 
85
87
  The SkillOpt harness at `scripts/dev/skillopt/` measures how accurately each skill guides an agent, and supports multiple providers (Anthropic, OpenAI-compat, Gemini, local models). See [`scripts/dev/skillopt/README.md`](scripts/dev/skillopt/README.md).
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.15.1] — 2026-06-10
11
+
12
+ ### Changed
13
+
14
+ - Added `--disable-dev-shm-usage` to Chrome launch args in both `FlowApiClient._persistent_context_kwargs()` and `UiAutomationTransport.setup()` — prevents OOM in Docker containers with the default 64 MB `/dev/shm` allocation; no effect on developer machines with adequate shared memory
15
+ - README Stats badges hardened against shields.io outages — GitHub-stat badges now pass `cacheSeconds=3600` (mitigates shields.io's shared GitHub token-pool exhaustion, the "Unable to select next GitHub token from pool" error) and the PyPI downloads badge moved from `img.shields.io/pypi/dm` to pepy.tech (pypistats rate-limits shields.io upstream)
16
+
17
+ ### Added
18
+
19
+ - `scripts/diag/` directory — documented home for investigation scripts that require a live authenticated profile; includes `memory_profile.py` (Chrome process-tree RSS profiler for issue #155), `capture_flow_traffic.py`, and `recaptcha_mint.py` (both moved from `scripts/` root via git mv, history preserved)
20
+
21
+ ### Fixed
22
+
23
+ - Video status poll now raises `AuthExpiredError` (exit 3) immediately on HTTP 401 from `batchCheckAsyncVideoGenerationStatus` instead of silently timing out after 600 s with a bare `TimeoutError` (exit 1) — session expiry is now detected mid-workflow, not only at login time (issue #156)
24
+
10
25
  ## [0.15.0] — 2026-06-09
11
26
 
12
27
  ### Added
@@ -1469,7 +1484,8 @@ shell-script template that branches on these codes.
1469
1484
 
1470
1485
  First skeleton. Not functional end-to-end yet.
1471
1486
 
1472
- [Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.15.0...HEAD
1487
+ [Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.15.1...HEAD
1488
+ [0.15.1]: https://github.com/ffroliva/gflow-cli/compare/v0.15.0...v0.15.1
1473
1489
  [0.15.0]: https://github.com/ffroliva/gflow-cli/compare/v0.14.0...v0.15.0
1474
1490
  [0.14.0]: https://github.com/ffroliva/gflow-cli/compare/v0.13.0...v0.14.0
1475
1491
  [0.13.0]: https://github.com/ffroliva/gflow-cli/compare/v0.12.0...v0.13.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gflow-cli
3
- Version: 0.15.0
3
+ Version: 0.15.1
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
@@ -196,13 +196,13 @@ gflow CLI → Provider (interchangeable) → Flow (ui_automation) / Mock (te
196
196
 
197
197
  ## Stats
198
198
 
199
- [![GitHub stars](https://img.shields.io/github/stars/ffroliva/gflow-cli?style=social)](https://github.com/ffroliva/gflow-cli/stargazers)
200
- [![GitHub forks](https://img.shields.io/github/forks/ffroliva/gflow-cli?style=social)](https://github.com/ffroliva/gflow-cli/network/members)
201
- [![GitHub watchers](https://img.shields.io/github/watchers/ffroliva/gflow-cli?style=social)](https://github.com/ffroliva/gflow-cli/watchers)
202
- [![GitHub issues](https://img.shields.io/github/issues/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli/issues)
203
- [![GitHub pull requests](https://img.shields.io/github/issues-pr/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli/pulls)
204
- [![GitHub last commit](https://img.shields.io/github/last-commit/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli/commits/main)
205
- [![GitHub repo size](https://img.shields.io/github/repo-size/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli)
206
- [![PyPI downloads](https://img.shields.io/pypi/dm/gflow-cli.svg)](https://pypi.org/project/gflow-cli/)
199
+ [![GitHub stars](https://img.shields.io/github/stars/ffroliva/gflow-cli?style=social&cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/stargazers)
200
+ [![GitHub forks](https://img.shields.io/github/forks/ffroliva/gflow-cli?style=social&cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/network/members)
201
+ [![GitHub watchers](https://img.shields.io/github/watchers/ffroliva/gflow-cli?style=social&cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/watchers)
202
+ [![GitHub issues](https://img.shields.io/github/issues/ffroliva/gflow-cli?cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/issues)
203
+ [![GitHub pull requests](https://img.shields.io/github/issues-pr/ffroliva/gflow-cli?cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/pulls)
204
+ [![GitHub last commit](https://img.shields.io/github/last-commit/ffroliva/gflow-cli?cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/commits/main)
205
+ [![GitHub repo size](https://img.shields.io/github/repo-size/ffroliva/gflow-cli?cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli)
206
+ [![PyPI downloads](https://static.pepy.tech/badge/gflow-cli/month)](https://pepy.tech/project/gflow-cli)
207
207
 
208
208
  If `gflow-cli` saves you time, please ⭐ the repo — it is the cheapest way to support the project.
@@ -132,13 +132,13 @@ gflow CLI → Provider (interchangeable) → Flow (ui_automation) / Mock (te
132
132
 
133
133
  ## Stats
134
134
 
135
- [![GitHub stars](https://img.shields.io/github/stars/ffroliva/gflow-cli?style=social)](https://github.com/ffroliva/gflow-cli/stargazers)
136
- [![GitHub forks](https://img.shields.io/github/forks/ffroliva/gflow-cli?style=social)](https://github.com/ffroliva/gflow-cli/network/members)
137
- [![GitHub watchers](https://img.shields.io/github/watchers/ffroliva/gflow-cli?style=social)](https://github.com/ffroliva/gflow-cli/watchers)
138
- [![GitHub issues](https://img.shields.io/github/issues/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli/issues)
139
- [![GitHub pull requests](https://img.shields.io/github/issues-pr/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli/pulls)
140
- [![GitHub last commit](https://img.shields.io/github/last-commit/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli/commits/main)
141
- [![GitHub repo size](https://img.shields.io/github/repo-size/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli)
142
- [![PyPI downloads](https://img.shields.io/pypi/dm/gflow-cli.svg)](https://pypi.org/project/gflow-cli/)
135
+ [![GitHub stars](https://img.shields.io/github/stars/ffroliva/gflow-cli?style=social&cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/stargazers)
136
+ [![GitHub forks](https://img.shields.io/github/forks/ffroliva/gflow-cli?style=social&cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/network/members)
137
+ [![GitHub watchers](https://img.shields.io/github/watchers/ffroliva/gflow-cli?style=social&cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/watchers)
138
+ [![GitHub issues](https://img.shields.io/github/issues/ffroliva/gflow-cli?cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/issues)
139
+ [![GitHub pull requests](https://img.shields.io/github/issues-pr/ffroliva/gflow-cli?cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/pulls)
140
+ [![GitHub last commit](https://img.shields.io/github/last-commit/ffroliva/gflow-cli?cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/commits/main)
141
+ [![GitHub repo size](https://img.shields.io/github/repo-size/ffroliva/gflow-cli?cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli)
142
+ [![PyPI downloads](https://static.pepy.tech/badge/gflow-cli/month)](https://pepy.tech/project/gflow-cli)
143
143
 
144
144
  If `gflow-cli` saves you time, please ⭐ the repo — it is the cheapest way to support the project.
@@ -37,6 +37,7 @@ Welcome to the `gflow-cli` documentation. This index is the routing layer: it te
37
37
  | **[tasks/lessons.md](../tasks/lessons.md)** | Running notebook of patterns + reviewer findings, dated and traced to commits | Starting a new phase; debugging "why did the council flag this?" |
38
38
  | **[skills/README.md](../skills/README.md)** | Installable agent skill docs (gflow-cli, predict, pr-council-review, scenario) — cross-tool portable Markdown consumed by Claude Code, Cursor, Codex, Gemini CLI, Aider, etc. | Any agent wanting to use gflow-cli correctly |
39
39
  | **[scripts/dev/skillopt/README.md](../scripts/dev/skillopt/README.md)** | SkillOpt mock harness — rollout→score loop for measuring and improving skill doc accuracy across multiple LLM providers | Measuring a skill edit's impact; comparing Claude vs GPT-4o vs Gemini on gflow tasks |
40
+ | **[scripts/diag/README.md](../scripts/diag/README.md)** | Diagnostic investigation scripts — run against a live authenticated profile to capture wire samples, measure Chrome memory, or mint reCAPTCHA tokens | Running a one-off investigation against a live Flow session; establishing baseline measurements for issue #155 |
40
41
 
41
42
  ## Agent commands
42
43
 
@@ -54,6 +55,9 @@ Slash commands for Claude Code, stored in `.claude/commands/gflow/`. All prefixe
54
55
  | `/gflow:release` | Full release flow (calls `/gflow:changelog` + `/gflow:check`) | Cutting a new version |
55
56
  | `/gflow:predict <proposal>` | 5-persona pre-implementation analysis → GO / CAUTION / STOP | Before any high-stakes design decision (new transport, auth change, selector redesign, schema migration) |
56
57
  | `/gflow:scenario <feature>` | 12-dimension edge-case explorer → severity-ranked scenario table + BDD skeleton | After predict GO/CAUTION; before `/gflow:plan` |
58
+ | `/gflow:pr-council-review [PR#]` | Multi-dimensional council review of an open PR (5 baseline + adaptive dimensions) | Before merging any non-trivial PR; mandatory for auth/transport/data changes |
59
+ | `/gflow:branch-review` | Same council review run against the current local feature branch (no PR needed) | Pre-PR self-audit; after predict/scenario on a high-stakes branch |
60
+ | `/gflow:doc-review` | Systematic council-driven audit of documentation completeness and drift | Before cutting a release; after major documentation changes |
57
61
 
58
62
  **Governance:** commands are executable docs — they decay like any doc. When a phase advances or a file path changes, update the relevant command in the same commit. `/gflow:release` includes a staleness review step.
59
63
 
@@ -90,6 +94,7 @@ Slash commands for Claude Code, stored in `.claude/commands/gflow/`. All prefixe
90
94
  **"How do I use this project's skills in Cursor / Codex / Gemini CLI / Aider?"** → [skills/README.md](../skills/README.md#use-with-other-agents)
91
95
  **"How do I benchmark a skill doc against real tasks?"** → [scripts/dev/skillopt/README.md](../scripts/dev/skillopt/README.md)
92
96
  **"How do I compare Claude vs GPT-4o vs Gemini on gflow tasks?"** → `python scripts/dev/skillopt/harness.py --provider openai --model gpt-4o` (see [skillopt README](../scripts/dev/skillopt/README.md))
97
+ **"What does Chrome actually use in RAM during a generation?"** → run `uv run python scripts/diag/memory_profile.py --profile NAME` (see [scripts/diag/README.md](../scripts/diag/README.md))
93
98
  **"How do I report a security issue?"** → [SECURITY § Reporting](SECURITY.md#reporting)
94
99
  **"What branch do I work on? How do I name it?"** → [DEVELOPMENT § Branching model](DEVELOPMENT.md#branching-model)
95
100
  **"How do I handle an external GitHub PR?"** → [GITHUB § Scenario Matrix](GITHUB.md#scenario-matrix)
@@ -104,7 +109,7 @@ Slash commands for Claude Code, stored in `.claude/commands/gflow/`. All prefixe
104
109
  **"A gflow command hangs / fails — where do I start?"** → [DEBUGGING § Quick reference](DEBUGGING.md#quick-reference)
105
110
  **"Flow's UI broke a selector — how do I diagnose it?"** → [DEBUGGING § Inspecting Flow's live UI](DEBUGGING.md#inspecting-flows-live-ui)
106
111
  **"What does each `ui_automation.*` log event mean?"** → [DEBUGGING § Listener & HTTP-layer debugging](DEBUGGING.md#listener--http-layer-debugging)
107
- **"What was actually live-verified for the latest release?"** → [LIVE_VERIFICATION_v0.13.0](LIVE_VERIFICATION_v0.13.0.md) · prior: [v0.12.0](LIVE_VERIFICATION_v0.12.0.md) · [v0.11.0](LIVE_VERIFICATION_v0.11.0.md) · [v0.10.0](LIVE_VERIFICATION_v0.10.0.md) · [v0.9.1](LIVE_VERIFICATION_v0.9.1.md)
112
+ **"What was actually live-verified for the latest release?"** → v0.15.0 / v0.14.x: no dedicated live-verification doc (CI + the v0.13.0 baseline). Latest doc: [LIVE_VERIFICATION_v0.13.0](LIVE_VERIFICATION_v0.13.0.md) · prior: [v0.12.0](LIVE_VERIFICATION_v0.12.0.md) · [v0.11.0](LIVE_VERIFICATION_v0.11.0.md) · [v0.10.0](LIVE_VERIFICATION_v0.10.0.md) · [v0.9.1](LIVE_VERIFICATION_v0.9.1.md)
108
113
  **"What was live-verified for the data layer (PR #58)?"** → [LIVE_VERIFICATION_data_layer](LIVE_VERIFICATION_data_layer.md) — 1 Imagen + 1 Veo credit on denon82, 6-layer ledger (file + magic + Pillow + DB rows + CLI round-trip + structlog)
109
114
  **"What was live-verified for the video-download feature (#29)?"** → [LIVE_VERIFICATION_video_download](LIVE_VERIFICATION_video_download.md)
110
115
  **"What is the jitter matrix evidence for `gflow image batch`?"** → [`LIVE_VERIFICATION_image_batch.md`](LIVE_VERIFICATION_image_batch.md) — jitter matrix evidence for `gflow image batch` (always-same-project mode)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "gflow-cli"
3
- version = "0.15.0"
3
+ version = "0.15.1"
4
4
  description = "Unofficial CLI for Google Flow — drive Veo image-to-video generations from the terminal."
5
5
  readme = "README.md"
6
6
  license = { file = "LICENSE" }
@@ -0,0 +1,29 @@
1
+ # scripts/diag/ — Diagnostic Investigation Scripts
2
+
3
+ These scripts require a live authenticated Chrome profile to run. They are investigation tools — not CI gates and not developer workflow tools — that help answer "what does this system actually do?" questions by observing a real browser session. Each script produces human-readable or structured output and does not modify production state.
4
+
5
+ ## Scripts
6
+
7
+ | Script | Purpose | Prerequisite | Run |
8
+ |---|---|---|---|
9
+ | `capture_flow_traffic.py` | Capture Flow's outgoing API requests via `page.route` | `gflow auth login` | `uv run python scripts/diag/capture_flow_traffic.py --profile NAME` |
10
+ | `recaptcha_mint.py` | What `site_key` + token does gflow-cli's `TokenMinter` produce? | `gflow auth login` (headed) | `uv run python scripts/diag/recaptcha_mint.py --profile NAME` |
11
+ | `memory_profile.py` | Chrome process-tree RSS at key milestones (issue #155) | `gflow auth login` + `pip install psutil` | `uv run python scripts/diag/memory_profile.py --profile NAME` |
12
+
13
+ ## What belongs here
14
+
15
+ 1. Requires a live authenticated session to run
16
+ 2. Produces human-readable or structured output for investigation
17
+ 3. Does not write to production data stores
18
+ 4. Answers a specific "what does this system actually do?" question
19
+
20
+ ## What does NOT belong here
21
+
22
+ - **CI gates** → `scripts/ci/` (run on every commit, no auth needed)
23
+ - **Developer workflow tools** → `scripts/dev/` (`active_plan.py`, `skillopt/`, etc.)
24
+ - **Live smoke tests** → `scripts/` root (`smoke_*.py` — full end-to-end generation runs)
25
+
26
+ ## Platform notes
27
+
28
+ - `memory_profile.py` requires `psutil`: `uv add --dev psutil` (not a hard dep — detected at runtime)
29
+ - All scripts: `uv run python scripts/diag/<name>.py` (no global Python install needed)
@@ -4,7 +4,7 @@ Spec § 11 mentioned a captured wire sample (samples/captured/06_batchGenerateIm
4
4
  but the file doesn't exist. This script produces that ground truth — what
5
5
  headers does Flow's UI actually attach when it calls aisandbox-pa?
6
6
 
7
- Run: `uv run python scripts/diag_capture_flow_traffic.py --profile <your-profile>`
7
+ Run: `uv run python scripts/diag/capture_flow_traffic.py --profile <your-profile>`
8
8
 
9
9
  Output goes to `tmp/captured/flow_outgoing_<utc>.jsonl` by default. **NEVER write
10
10
  captured traffic to `samples/captured/`** — those files contain live Bearer tokens
@@ -0,0 +1,235 @@
1
+ """Diagnostic — Chrome process-tree RSS at key milestones (issue #155).
2
+
3
+ Measures how much memory the Chrome/Chromium process tree consumes at four
4
+ points during a real browser launch against a gflow-cli profile:
5
+
6
+ baseline — before Playwright starts (current Python process only)
7
+ post_launch — immediately after launch_persistent_context returns
8
+ post_navigation — after page.goto(FLOW_URL, wait_until="networkidle")
9
+ post_close — after context.close() and Playwright stop
10
+
11
+ The output table shows Own RSS (the profiler's Python process) and Tree RSS
12
+ (profiler + all Chrome child processes) so you can see exactly how much RAM
13
+ Chrome adds at each stage.
14
+
15
+ Run: `uv run python scripts/diag/memory_profile.py --profile NAME [--output-json PATH]`
16
+
17
+ Prerequisite: gflow auth login (plus psutil — install with: uv add --dev psutil)
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import argparse
23
+ import asyncio
24
+ import json
25
+ import os
26
+ import sys
27
+ from pathlib import Path
28
+
29
+ try:
30
+ import psutil
31
+ except ImportError:
32
+ print("psutil is required: uv add --dev psutil", file=sys.stderr)
33
+ sys.exit(2)
34
+
35
+ try:
36
+ from gflow_cli.api.transports.ui_automation import FLOW_URL
37
+ except ImportError:
38
+ FLOW_URL = "https://labs.google/fx/tools/flow?hl=en"
39
+
40
+ from playwright.async_api import async_playwright
41
+
42
+ from gflow_cli.auth import profile_dir
43
+ from gflow_cli.browser_manager import channel_for_profile
44
+ from gflow_cli.config import get_settings
45
+
46
+ CHROME_ARGS = [
47
+ "--disable-blink-features=AutomationControlled",
48
+ "--disable-dev-shm-usage",
49
+ ]
50
+
51
+ _COL_MILESTONE = 16
52
+ _COL_OWN = 14
53
+ _COL_TREE = 15
54
+ _COL_DELTA = 12
55
+
56
+
57
+ def _tree_rss_mb(pid: int) -> float:
58
+ """Return total RSS (MB) of a process and all its descendants."""
59
+ try:
60
+ proc = psutil.Process(pid)
61
+ procs = [proc, *proc.children(recursive=True)]
62
+ return sum(p.memory_info().rss for p in procs if p.is_running()) / (1024 * 1024)
63
+ except (psutil.NoSuchProcess, psutil.AccessDenied):
64
+ return 0.0
65
+
66
+
67
+ def _own_rss_mb() -> float:
68
+ """Return RSS (MB) of only the current Python process."""
69
+ try:
70
+ return psutil.Process(os.getpid()).memory_info().rss / (1024 * 1024)
71
+ except (psutil.NoSuchProcess, psutil.AccessDenied):
72
+ return 0.0
73
+
74
+
75
+ def _print_table_header() -> None:
76
+ header = (
77
+ f"{'Milestone':<{_COL_MILESTONE}} | "
78
+ f"{'Own RSS (MB)':>{_COL_OWN}} | "
79
+ f"{'Tree RSS (MB)':>{_COL_TREE}} | "
80
+ f"{'Delta (MB)':>{_COL_DELTA}}"
81
+ )
82
+ sep = "-" * len(header)
83
+ print(sep)
84
+ print(header)
85
+ print(sep)
86
+
87
+
88
+ def _print_table_row(name: str, own_mb: float, tree_mb: float, delta: float | None) -> None:
89
+ delta_str = "—" if delta is None else f"{delta:+.1f}"
90
+ print(
91
+ f"{name:<{_COL_MILESTONE}} | "
92
+ f"{own_mb:>{_COL_OWN}.1f} | "
93
+ f"{tree_mb:>{_COL_TREE}.1f} | "
94
+ f"{delta_str:>{_COL_DELTA}}"
95
+ )
96
+
97
+
98
+ async def run(profile_name: str, output_json: Path | None) -> None:
99
+ """Main diagnostic loop."""
100
+ # Resolve profile directory using GFLOW_CLI_HOME
101
+ settings = get_settings()
102
+ _ = settings.home # ensure settings loaded; profile_dir() uses get_settings() internally
103
+ pdir = profile_dir(profile_name)
104
+ if not pdir.exists():
105
+ print(f"ERROR: Profile directory not found: {pdir}", file=sys.stderr)
106
+ sys.exit(1)
107
+
108
+ milestones: list[dict[str, object]] = []
109
+ pid = os.getpid()
110
+
111
+ # -------------------------------------------------------------------------
112
+ # Milestone 1: baseline (before Playwright starts)
113
+ # -------------------------------------------------------------------------
114
+ own_baseline = _own_rss_mb()
115
+ tree_baseline = _tree_rss_mb(pid)
116
+ milestones.append(
117
+ {
118
+ "name": "baseline",
119
+ "own_rss_mb": round(own_baseline, 2),
120
+ "tree_rss_mb": round(tree_baseline, 2),
121
+ "delta_mb": None,
122
+ }
123
+ )
124
+
125
+ _print_table_header()
126
+ _print_table_row("baseline", own_baseline, tree_baseline, None)
127
+
128
+ channel = channel_for_profile(pdir)
129
+
130
+ async with async_playwright() as pw:
131
+ launcher = pw.chromium
132
+
133
+ # -------------------------------------------------------------------------
134
+ # Milestone 2: post_launch
135
+ # -------------------------------------------------------------------------
136
+ ctx = await launcher.launch_persistent_context(
137
+ str(pdir),
138
+ headless=False,
139
+ args=CHROME_ARGS,
140
+ locale="en-US",
141
+ **({"channel": channel} if channel else {}),
142
+ )
143
+
144
+ own_post_launch = _own_rss_mb()
145
+ tree_post_launch = _tree_rss_mb(pid)
146
+ delta_launch = tree_post_launch - tree_baseline
147
+ milestones.append(
148
+ {
149
+ "name": "post_launch",
150
+ "own_rss_mb": round(own_post_launch, 2),
151
+ "tree_rss_mb": round(tree_post_launch, 2),
152
+ "delta_mb": round(delta_launch, 2),
153
+ }
154
+ )
155
+ _print_table_row("post_launch", own_post_launch, tree_post_launch, delta_launch)
156
+
157
+ # -------------------------------------------------------------------------
158
+ # Milestone 3: post_navigation
159
+ # -------------------------------------------------------------------------
160
+ page = ctx.pages[0] if ctx.pages else await ctx.new_page()
161
+ print(f"Navigating to {FLOW_URL} ...")
162
+ try:
163
+ await page.goto(FLOW_URL, wait_until="networkidle", timeout=45_000)
164
+ except Exception as exc: # noqa: BLE001
165
+ print(f"WARNING: navigation did not fully settle: {exc}", file=sys.stderr)
166
+
167
+ own_post_nav = _own_rss_mb()
168
+ tree_post_nav = _tree_rss_mb(pid)
169
+ delta_nav = tree_post_nav - tree_baseline
170
+ milestones.append(
171
+ {
172
+ "name": "post_navigation",
173
+ "own_rss_mb": round(own_post_nav, 2),
174
+ "tree_rss_mb": round(tree_post_nav, 2),
175
+ "delta_mb": round(delta_nav, 2),
176
+ }
177
+ )
178
+ _print_table_row("post_navigation", own_post_nav, tree_post_nav, delta_nav)
179
+
180
+ # -------------------------------------------------------------------------
181
+ # Milestone 4: post_close
182
+ # -------------------------------------------------------------------------
183
+ await ctx.close()
184
+
185
+ own_post_close = _own_rss_mb()
186
+ tree_post_close = _tree_rss_mb(pid)
187
+ delta_close = tree_post_close - tree_baseline
188
+ milestones.append(
189
+ {
190
+ "name": "post_close",
191
+ "own_rss_mb": round(own_post_close, 2),
192
+ "tree_rss_mb": round(tree_post_close, 2),
193
+ "delta_mb": round(delta_close, 2),
194
+ }
195
+ )
196
+ _print_table_row("post_close", own_post_close, tree_post_close, delta_close)
197
+ print("-" * (_COL_MILESTONE + _COL_OWN + _COL_TREE + _COL_DELTA + 9))
198
+
199
+ # -------------------------------------------------------------------------
200
+ # JSON output (optional)
201
+ # -------------------------------------------------------------------------
202
+ if output_json is not None:
203
+ result = {
204
+ "platform": sys.platform,
205
+ "chrome_args": CHROME_ARGS,
206
+ "milestones": milestones,
207
+ }
208
+ output_json.parent.mkdir(parents=True, exist_ok=True)
209
+ output_json.write_text(json.dumps(result, indent=2), encoding="utf-8")
210
+ print(f"JSON written to: {output_json}")
211
+
212
+
213
+ def main() -> None:
214
+ parser = argparse.ArgumentParser(
215
+ description=__doc__,
216
+ formatter_class=argparse.RawDescriptionHelpFormatter,
217
+ )
218
+ parser.add_argument(
219
+ "--profile",
220
+ required=True,
221
+ help="Name of the gflow-cli profile (directory under GFLOW_CLI_HOME)",
222
+ )
223
+ parser.add_argument(
224
+ "--output-json",
225
+ type=Path,
226
+ default=None,
227
+ metavar="PATH",
228
+ help="Optional path to write machine-readable results as JSON",
229
+ )
230
+ args = parser.parse_args()
231
+ asyncio.run(run(args.profile, args.output_json))
232
+
233
+
234
+ if __name__ == "__main__":
235
+ main()
@@ -1,6 +1,6 @@
1
1
  """Diagnostic — what site_key + token does gflow-cli's TokenMinter produce?
2
2
 
3
- Run: `uv run python scripts/diag_recaptcha_mint.py --profile <your-profile>`
3
+ Run: `uv run python scripts/diag/recaptcha_mint.py --profile <your-profile>`
4
4
 
5
5
  Opens HEADED Chromium, navigates to Flow, runs TokenMinter, prints the
6
6
  discovered site_key + minted token length. Compare to HAR ground truth:
@@ -1,3 +1,3 @@
1
1
  """gflow-cli — unofficial CLI for Google Flow."""
2
2
 
3
- __version__ = "0.15.0"
3
+ __version__ = "0.15.1"
@@ -293,7 +293,7 @@ class FlowApiClient:
293
293
  "--no-sandbox",
294
294
  "--password-store=basic",
295
295
  ],
296
- "args": ["--disable-blink-features=AutomationControlled"],
296
+ "args": ["--disable-blink-features=AutomationControlled", "--disable-dev-shm-usage"],
297
297
  }
298
298
 
299
299
  async def _enter_setup(self) -> None:
@@ -677,6 +677,7 @@ class UiAutomationTransport(VideoGenerationMixin):
677
677
  args=[
678
678
  "--disable-blink-features=AutomationControlled",
679
679
  "--password-store=basic",
680
+ "--disable-dev-shm-usage",
680
681
  ],
681
682
  )
682
683
  # Hide the automation flag so reCAPTCHA Enterprise doesn't score
@@ -522,6 +522,15 @@ class VideoGenerationMixin:
522
522
  while time.monotonic() < deadline:
523
523
  terminal: VideoStatus | None = None
524
524
  for response in captured_status:
525
+ if response.get("status") == 401:
526
+ raise AuthExpiredError(
527
+ detail=(
528
+ "batchCheckAsyncVideoGenerationStatus returned HTTP 401"
529
+ " — session expired mid-poll"
530
+ ),
531
+ status=401,
532
+ route="video:status",
533
+ )
525
534
  try:
526
535
  status = parse_video_status(response.get("body") or {}, media_id=media_name)
527
536
  except ValueError:
@@ -0,0 +1,77 @@
1
+ """Pins the ``FlowApiClient._persistent_context_kwargs()`` seam.
2
+
3
+ The seam was extracted from the inline ``launch_persistent_context(...)`` call so
4
+ a dev-scoped recording subclass can augment the launch without any recording
5
+ concern living in core (see ``scripts/dev/_recording_client.py``). This test
6
+ proves the extraction is value-for-value behavior-preserving and keeps the
7
+ seam's contract stable.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from pathlib import Path
13
+ from unittest.mock import AsyncMock, MagicMock, patch
14
+
15
+ import pytest
16
+
17
+ from gflow_cli.api.client import FlowApiClient
18
+ from gflow_cli.api.transports.ui_automation import UiAutomationTransport
19
+
20
+
21
+ def test_persistent_context_kwargs_are_unchanged(tmp_path: Path) -> None:
22
+ """The seam returns exactly the kwargs the client launched with before the
23
+ refactor — proving the extraction changed no behavior."""
24
+ client = FlowApiClient(profile_dir=tmp_path, headless=True)
25
+ kwargs = client._persistent_context_kwargs() # noqa: SLF001
26
+ assert kwargs["user_data_dir"] == str(tmp_path)
27
+ assert kwargs["headless"] is True
28
+ assert kwargs["viewport"] == {"width": 1280, "height": 720}
29
+ assert kwargs["locale"] == "en-US"
30
+ assert kwargs["extra_http_headers"] == {"Accept-Language": "en-US,en;q=0.9"}
31
+ assert kwargs["ignore_default_args"] == [
32
+ "--enable-automation",
33
+ "--no-sandbox",
34
+ "--password-store=basic",
35
+ ]
36
+ assert kwargs["args"] == [
37
+ "--disable-blink-features=AutomationControlled",
38
+ "--disable-dev-shm-usage",
39
+ ]
40
+ # channel is profile-derived; a marker-less tmp_path has no
41
+ # .gflow_browser_strategy file, so channel_for_profile() returns None.
42
+ assert kwargs["channel"] is None
43
+
44
+
45
+ @pytest.mark.asyncio
46
+ async def test_ui_automation_setup_passes_disable_dev_shm_usage(tmp_path: Path) -> None:
47
+ """setup() must pass --disable-dev-shm-usage in args to launch_persistent_context."""
48
+ fake_page = MagicMock()
49
+ fake_page.goto = AsyncMock()
50
+ fake_page.add_init_script = AsyncMock()
51
+
52
+ fake_ctx = MagicMock()
53
+ fake_ctx.pages = [fake_page]
54
+ fake_ctx.add_init_script = AsyncMock()
55
+
56
+ fake_chromium = MagicMock()
57
+ fake_chromium.launch_persistent_context = AsyncMock(return_value=fake_ctx)
58
+
59
+ fake_pw = MagicMock()
60
+ fake_pw.chromium = fake_chromium
61
+
62
+ mock_cm = MagicMock()
63
+ mock_cm.__aenter__ = AsyncMock(return_value=fake_pw)
64
+ mock_cm.__aexit__ = AsyncMock(return_value=False)
65
+
66
+ mock_async_playwright = MagicMock(return_value=mock_cm)
67
+
68
+ with patch("gflow_cli.api.transports.ui_automation.async_playwright", mock_async_playwright):
69
+ transport = UiAutomationTransport()
70
+ await transport.setup(profile_dir=tmp_path)
71
+
72
+ _call_kwargs = fake_chromium.launch_persistent_context.call_args
73
+ args_passed = _call_kwargs.kwargs.get(
74
+ "args",
75
+ _call_kwargs.args[1] if len(_call_kwargs.args) > 1 else [],
76
+ )
77
+ assert "--disable-dev-shm-usage" in args_passed
@@ -17,7 +17,7 @@ from gflow_cli.api.transports.ui_automation_video import (
17
17
  VideoGenerationMixin,
18
18
  )
19
19
  from gflow_cli.api.video import Aspect, GenerateVideoRequest, Mode, VideoModel, VideoStatus
20
- from gflow_cli.errors import WireFormatError
20
+ from gflow_cli.errors import AuthExpiredError, WireFormatError
21
21
 
22
22
 
23
23
  def _make_listener_page() -> tuple[MagicMock, list]:
@@ -145,6 +145,31 @@ class TestPollVideoStatus:
145
145
  page, [], "m", timeout_s=0.2, poll_interval_s=0.05
146
146
  )
147
147
 
148
+ @pytest.mark.asyncio
149
+ async def test_401_response_raises_auth_expired_error_immediately(self) -> None:
150
+ page = MagicMock()
151
+ captured = [
152
+ {"status": 401, "url": _STATUS_URL, "body": {}},
153
+ ]
154
+ with pytest.raises(AuthExpiredError, match="session expired mid-poll"):
155
+ await VideoGenerationMixin._poll_video_status(
156
+ page, captured, "m", timeout_s=60.0, poll_interval_s=0.05
157
+ )
158
+
159
+ @pytest.mark.asyncio
160
+ async def test_401_after_in_progress_raises_auth_expired_error(self) -> None:
161
+ page = MagicMock()
162
+ # Simulates session expiry mid-poll: some ACTIVE responses arrive first, then a 401
163
+ captured: list[dict[str, Any]] = [
164
+ _status_resp("m", "MEDIA_GENERATION_STATUS_SCHEDULED"),
165
+ _status_resp("m", "MEDIA_GENERATION_STATUS_ACTIVE"),
166
+ {"status": 401, "url": _STATUS_URL, "body": {}},
167
+ ]
168
+ with pytest.raises(AuthExpiredError, match="session expired mid-poll"):
169
+ await VideoGenerationMixin._poll_video_status(
170
+ page, captured, "m", timeout_s=60.0, poll_interval_s=0.05
171
+ )
172
+
148
173
 
149
174
  def _cascade_page(visible: set[str]) -> MagicMock:
150
175
  """A fake page whose locator(sel) is 'visible' only for sel in `visible`."""
@@ -28,4 +28,7 @@ def test_recording_client_injects_video_and_preserves_base(tmp_path: Path) -> No
28
28
  # Base kwargs preserved untouched:
29
29
  assert kwargs["user_data_dir"] == str(tmp_path)
30
30
  assert kwargs["headless"] is True
31
- assert kwargs["args"] == ["--disable-blink-features=AutomationControlled"]
31
+ assert kwargs["args"] == [
32
+ "--disable-blink-features=AutomationControlled",
33
+ "--disable-dev-shm-usage",
34
+ ]
@@ -750,7 +750,7 @@ wheels = [
750
750
 
751
751
  [[package]]
752
752
  name = "gflow-cli"
753
- version = "0.15.0"
753
+ version = "0.15.1"
754
754
  source = { editable = "." }
755
755
  dependencies = [
756
756
  { name = "click" },