ruff-sync 0.1.6.dev4__tar.gz → 0.1.7.dev2__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 (210) hide show
  1. ruff_sync-0.1.7.dev2/.agents/cli_animation_plan.md +710 -0
  2. ruff_sync-0.1.7.dev2/.agents/workflows/update-recordings.md +72 -0
  3. ruff_sync-0.1.7.dev2/.github/workflows/codspeed.yaml +37 -0
  4. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/PKG-INFO +7 -2
  5. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/README.md +5 -0
  6. ruff_sync-0.1.7.dev2/docs/assets/recordings/check_drift.gif +0 -0
  7. ruff_sync-0.1.7.dev2/docs/assets/recordings/check_in_sync.gif +0 -0
  8. ruff_sync-0.1.7.dev2/docs/assets/recordings/help_overview.gif +0 -0
  9. ruff_sync-0.1.7.dev2/docs/assets/recordings/init_project.gif +0 -0
  10. ruff_sync-0.1.7.dev2/docs/assets/recordings/pull_basic.gif +0 -0
  11. ruff_sync-0.1.7.dev2/docs/assets/recordings/validate_strict.gif +0 -0
  12. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/ci-integration.md +6 -0
  13. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/gen_ref_pages.py +1 -1
  14. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/index.md +4 -0
  15. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/usage.md +8 -0
  16. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/pyproject.toml +15 -3
  17. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/cli.py +1 -1
  18. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/config_io.py +1 -1
  19. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/core.py +7 -6
  20. ruff_sync-0.1.7.dev2/tapes/_common.tape +21 -0
  21. ruff_sync-0.1.7.dev2/tapes/check_drift.tape +38 -0
  22. ruff_sync-0.1.7.dev2/tapes/check_in_sync.tape +20 -0
  23. ruff_sync-0.1.7.dev2/tapes/help_overview.tape +27 -0
  24. ruff_sync-0.1.7.dev2/tapes/init_project.tape +36 -0
  25. ruff_sync-0.1.7.dev2/tapes/pull_basic.tape +32 -0
  26. ruff_sync-0.1.7.dev2/tapes/validate_strict.tape +24 -0
  27. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tasks.py +56 -1
  28. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/conftest.py +56 -3
  29. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_basic.py +18 -23
  30. ruff_sync-0.1.7.dev2/tests/test_benchmarks.py +338 -0
  31. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_check.py +43 -32
  32. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_config_validation.py +13 -8
  33. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_deprecation.py +6 -5
  34. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_e2e.py +13 -8
  35. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_formatters.py +2 -2
  36. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_git_fetch.py +1 -1
  37. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_scaffold.py +3 -3
  38. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_serialization.py +1 -1
  39. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_url_handling.py +7 -6
  40. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/uv.lock +355 -187
  41. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/DEPENDENCIES.md +0 -0
  42. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/TESTING.md +0 -0
  43. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/args_refactor_plan.md +0 -0
  44. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/decisions/0001-type-refactoring-strategy.md +0 -0
  45. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/decisions/0002-tui-node-ast.md +0 -0
  46. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/decisions/0003-argument-resolution-layers.md +0 -0
  47. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/decisions/README.md +0 -0
  48. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/doc-fix.md +0 -0
  49. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/docs_update_plan.md +0 -0
  50. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/formatters-architecture.md +0 -0
  51. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/gitlab-reports.md +0 -0
  52. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/issue-102-context.md +0 -0
  53. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/plans/issue-100-roadmap-plan.md +0 -0
  54. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/plans/issue-116-config-validation.md +0 -0
  55. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/ruff.toml +0 -0
  56. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/adr/SKILL.md +0 -0
  57. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/dirty-equals/SKILL.md +0 -0
  58. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/dirty-equals/references/common-matchers.md +0 -0
  59. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/dirty-equals/references/toml-matching.md +0 -0
  60. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/dirty-equals/trigger_eval.json +0 -0
  61. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/gh-issues/SKILL.md +0 -0
  62. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/mike/SKILL.md +0 -0
  63. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/mike/references/commands.md +0 -0
  64. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/mkdocs-generation/SKILL.md +0 -0
  65. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/mkdocs-generation/examples.md +0 -0
  66. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/mkdocs-generation/templates/api-reference.md +0 -0
  67. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/mkdocs-generation/templates/getting-started.md +0 -0
  68. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/mkdocs-generation/templates/index.md +0 -0
  69. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/mkdocs-generation/templates/mkdocs.yml +0 -0
  70. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/release-notes-generation/SKILL.md +0 -0
  71. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/ruff-sync-usage/SKILL.md +0 -0
  72. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/ruff-sync-usage/references/ci-integration.md +0 -0
  73. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/ruff-sync-usage/references/configuration.md +0 -0
  74. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/ruff-sync-usage/references/troubleshooting.md +0 -0
  75. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/skill-creator/SKILL.md +0 -0
  76. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/skill-creator/references/best-practices.md +0 -0
  77. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/skill-creator/references/evaluating-skills.md +0 -0
  78. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/skill-creator/references/optimizing-descriptions.md +0 -0
  79. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/skill-creator/references/quickstart.md +0 -0
  80. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/skill-creator/references/sources.md +0 -0
  81. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/skill-creator/references/using-scripts.md +0 -0
  82. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/skill-creator/scripts/scaffold_skill.py +0 -0
  83. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/textual/SKILL.md +0 -0
  84. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/textual/examples/basic_app.py +0 -0
  85. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/textual/examples/reactive_example.py +0 -0
  86. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/textual/references/events.md +0 -0
  87. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/textual/references/styling.md +0 -0
  88. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/textual/references/testing.md +0 -0
  89. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/textual/references/widgets.md +0 -0
  90. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/type-checking/SKILL.md +0 -0
  91. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/type-checking/evals.json +0 -0
  92. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/type-checking/references/advanced-narrowing.md +0 -0
  93. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/type-checking/references/error-code-lookup.md +0 -0
  94. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/type-checking/references/generics.md +0 -0
  95. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/type-checking/references/naming.md +0 -0
  96. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/type-checking/references/protocol-patterns.md +0 -0
  97. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/type-checking/references/quickstart.md +0 -0
  98. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/type-checking/references/refactoring-patterns.md +0 -0
  99. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/type-checking/scripts/audit_types.py +0 -0
  100. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/skills/warnings-control/SKILL.md +0 -0
  101. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/tui_design.md +0 -0
  102. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/tui_requirements.md +0 -0
  103. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/tui_rule_browsing.md +0 -0
  104. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/tui_rule_browsing_design.md +0 -0
  105. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/workflows/add-test-case.md +0 -0
  106. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.agents/workflows/update-screenshots.md +0 -0
  107. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.git-blame-ignore-revs +0 -0
  108. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.github/dependabot.yml +0 -0
  109. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.github/workflows/ci.yaml +0 -0
  110. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.github/workflows/complexity.yaml +0 -0
  111. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.gitignore +0 -0
  112. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.pre-commit-config.yaml +0 -0
  113. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/.pre-commit-hooks.yaml +0 -0
  114. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/AGENTS.md +0 -0
  115. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/CONTRIBUTING.md +0 -0
  116. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/LICENSE.md +0 -0
  117. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/codecov.yml +0 -0
  118. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/configs/data-science-engineering/ruff.toml +0 -0
  119. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/configs/fastapi/ruff.toml +0 -0
  120. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/configs/kitchen-sink/ruff.toml +0 -0
  121. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/agent-skill.md +0 -0
  122. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/assets/favicon.png +0 -0
  123. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/assets/github-job-summary.png +0 -0
  124. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/assets/github-pr-annotation.png +0 -0
  125. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/assets/inspect-main.png +0 -0
  126. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/assets/inspect-search.png +0 -0
  127. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/assets/logo.png +0 -0
  128. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/assets/ruff_sync_banner.png +0 -0
  129. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/assets/screenshots/dashboard.svg +0 -0
  130. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/assets/screenshots/legend_help.svg +0 -0
  131. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/assets/screenshots/rule_details.svg +0 -0
  132. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/assets/screenshots/screenshot_sample.toml +0 -0
  133. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/assets/screenshots/search_omnibox.svg +0 -0
  134. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/best-practices.md +0 -0
  135. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/configuration.md +0 -0
  136. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/contributing.md +0 -0
  137. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/examples/advanced-config.toml +0 -0
  138. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/examples/basic-config.toml +0 -0
  139. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/inspect.md +0 -0
  140. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/installation.md +0 -0
  141. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/overrides/main.html +0 -0
  142. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/overrides/partials/version_warning.html +0 -0
  143. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/pre-commit.md +0 -0
  144. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/pre-defined-configs.md +0 -0
  145. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/troubleshooting.md +0 -0
  146. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/docs/url-resolution.md +0 -0
  147. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/mkdocs.yml +0 -0
  148. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/scripts/check_dogfood.sh +0 -0
  149. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/scripts/generate_tui_screenshots.py +0 -0
  150. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/scripts/gitclone_dogfood.sh +0 -0
  151. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/scripts/pull_dogfood.sh +0 -0
  152. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/skills-lock.json +0 -0
  153. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/__init__.py +0 -0
  154. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/__main__.py +0 -0
  155. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/constants.py +0 -0
  156. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/dependencies.py +0 -0
  157. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/formatters.py +0 -0
  158. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/pre_commit.py +0 -0
  159. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/system.py +0 -0
  160. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/tui/__init__.py +0 -0
  161. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/tui/app.py +0 -0
  162. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/tui/constants.py +0 -0
  163. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/tui/screens.py +0 -0
  164. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/tui/themes.py +0 -0
  165. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/tui/types_.py +0 -0
  166. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/tui/widgets.py +0 -0
  167. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/types_.py +0 -0
  168. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/src/ruff_sync/validation.py +0 -0
  169. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/__init__.py +0 -0
  170. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/multi_upstream_final.toml +0 -0
  171. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/multi_upstream_initial.toml +0 -0
  172. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/multi_upstream_up1.toml +0 -0
  173. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/multi_upstream_up2.toml +0 -0
  174. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/no_changes_final.toml +0 -0
  175. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/no_changes_initial.toml +0 -0
  176. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/no_changes_upstream.toml +0 -0
  177. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/no_dotted_keys_final.toml +0 -0
  178. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/no_dotted_keys_initial.toml +0 -0
  179. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/no_dotted_keys_upstream.toml +0 -0
  180. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/no_ruff_cfg_final.toml +0 -0
  181. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/no_ruff_cfg_initial.toml +0 -0
  182. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/no_ruff_cfg_upstream.toml +0 -0
  183. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/readme_excludes_final.toml +0 -0
  184. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/readme_excludes_initial.toml +0 -0
  185. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/readme_excludes_upstream.toml +0 -0
  186. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/standard_final.toml +0 -0
  187. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/standard_initial.toml +0 -0
  188. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/lifecycle_tomls/standard_upstream.toml +0 -0
  189. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/ruff.toml +0 -0
  190. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_ci_integration.py +0 -0
  191. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_ci_validation.py +0 -0
  192. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_config_io.py +0 -0
  193. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_constants.py +0 -0
  194. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_corner_cases.py +0 -0
  195. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_dependencies.py +0 -0
  196. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_minimal_imports.sh +0 -0
  197. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_pre_commit.py +0 -0
  198. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_project.py +0 -0
  199. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_rule_logic.py +0 -0
  200. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_system.py +0 -0
  201. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_toml_operations.py +0 -0
  202. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/test_whitespace.py +0 -0
  203. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/tui/__init__.py +0 -0
  204. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/tui/conftest.py +0 -0
  205. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/tui/test_themes.py +0 -0
  206. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/tui/test_tui.py +0 -0
  207. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/tui/test_tui_types.py +0 -0
  208. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/w_ruff_sync_cfg/pyproject.toml +0 -0
  209. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/wo_ruff_cfg/pyproject.toml +0 -0
  210. {ruff_sync-0.1.6.dev4 → ruff_sync-0.1.7.dev2}/tests/wo_ruff_sync_cfg/pyproject.toml +0 -0
@@ -0,0 +1,710 @@
1
+ # CLI Animation Plan for ruff-sync Documentation
2
+
3
+ ## Goal
4
+
5
+ Add polished terminal GIF animations to `README.md` and the MkDocs documentation site to showcase ruff-sync's key workflows visually. Use a tool that produces **deterministic, version-controlled, agent-automatable** recordings.
6
+
7
+ ---
8
+
9
+ ## Tool Selection: Charmbracelet VHS
10
+
11
+ **[VHS](https://github.com/charmbracelet/vhs)** (19k+ ★) is the clear winner for this project. Here's why:
12
+
13
+ | Criterion | VHS | asciinema | terminalizer |
14
+ |---|---|---|---|
15
+ | Deterministic (code-as-config) | ✅ `.tape` files | ❌ records live | ❌ records live |
16
+ | GIF output | ✅ native | ⚠️ needs agg/svg-term | ✅ native |
17
+ | AI-agent friendly | ✅ simple DSL, text files | ❌ interactive recording | ❌ interactive recording |
18
+ | Version-controllable | ✅ tape files in git | ❌ JSON recordings | ❌ YAML recordings |
19
+ | Theming | ✅ built-in themes | ✅ | ⚠️ |
20
+ | CI-compatible | ✅ Docker image available | ⚠️ | ❌ |
21
+
22
+ ### Why VHS is Agent-Friendly
23
+
24
+ VHS uses plain-text `.tape` files with a simple DSL (`Type`, `Enter`, `Sleep`, `Set`). An AI agent can:
25
+
26
+ 1. **Write** tape files from scratch (just text)
27
+ 2. **Edit** existing tape files to update commands when CLI behavior changes
28
+ 3. **Run** `vhs <file>.tape` non-interactively to regenerate GIFs
29
+ 4. **Validate** tape files syntactically with `vhs validate <file>.tape`
30
+
31
+ No UI interaction, no screen recording, no manual timing — everything is declarative.
32
+
33
+ ---
34
+
35
+ ## Prerequisites
36
+
37
+ ### Install VHS and its dependencies
38
+
39
+ VHS requires `ttyd` and `ffmpeg` to be installed alongside it.
40
+
41
+ ```bash
42
+ brew install vhs
43
+ # This also installs ttyd and ffmpeg as dependencies on macOS via Homebrew
44
+ ```
45
+
46
+ Verify the installation:
47
+
48
+ ```bash
49
+ vhs --version
50
+ which ttyd
51
+ which ffmpeg
52
+ ```
53
+
54
+ ### Install ruff-sync in the environment
55
+
56
+ The tape files will run `ruff-sync` commands, so it must be callable:
57
+
58
+ ```bash
59
+ # From the project root:
60
+ uv pip install -e .
61
+ ```
62
+
63
+ ---
64
+
65
+ ## Directory Structure
66
+
67
+ Create the following directory structure:
68
+
69
+ ```
70
+ docs/
71
+ assets/
72
+ recordings/ # ← NEW: output GIFs go here
73
+ pull_basic.gif
74
+ check_drift.gif
75
+ init_project.gif
76
+ check_in_sync.gif
77
+ validate_strict.gif
78
+ help_overview.gif
79
+ tapes/ # ← NEW: VHS tape source files
80
+ _common.tape # shared settings (sourced by all tapes)
81
+ pull_basic.tape
82
+ check_drift.tape
83
+ init_project.tape
84
+ check_in_sync.tape
85
+ validate_strict.tape
86
+ help_overview.tape
87
+ ```
88
+
89
+ ### Step-by-step directory creation
90
+
91
+ ```bash
92
+ mkdir -p docs/assets/recordings
93
+ mkdir -p tapes
94
+ ```
95
+
96
+ ### Add `docs/assets/recordings/` to `.gitignore` (optional)
97
+
98
+ If GIFs should be tracked in git (recommended for docs), do NOT add them to `.gitignore`. If they should be regenerated in CI only, add:
99
+
100
+ ```
101
+ # .gitignore
102
+ docs/assets/recordings/*.gif
103
+ ```
104
+
105
+ > [!IMPORTANT]
106
+ > **Recommendation**: Track the GIFs in git so they display on GitHub without CI. They are usually 200-500 KB each.
107
+
108
+ ---
109
+
110
+ ## Tape Files
111
+
112
+ ### Shared Settings: `tapes/_common.tape`
113
+
114
+ This file defines the visual settings reused by all tape files via VHS's `Source` command.
115
+
116
+ ```tape
117
+ # tapes/_common.tape
118
+ # Shared VHS settings for ruff-sync documentation recordings.
119
+ #
120
+ # All individual tape files should `Source` this file at the top.
121
+
122
+ # ── Terminal appearance ──────────────────────────────────────────
123
+ Set Shell "bash"
124
+ Set FontFamily "JetBrains Mono"
125
+ Set FontSize 16
126
+ Set Width 1200
127
+ Set Height 600
128
+ Set LetterSpacing 1
129
+ Set LineHeight 1.2
130
+ Set Padding 20
131
+ Set Theme "Catppuccin Mocha"
132
+
133
+ # ── Typing behavior ─────────────────────────────────────────────
134
+ Set TypingSpeed 40ms
135
+
136
+ # ── Cursor ───────────────────────────────────────────────────────
137
+ Set CursorBlink false
138
+ ```
139
+
140
+ > [!NOTE]
141
+ > The `Source` command in VHS lets tape files inherit settings from `_common.tape`. This keeps styling consistent and editable from one place.
142
+
143
+ ---
144
+
145
+ ### Tape 1: `tapes/pull_basic.tape` — Basic Sync
146
+
147
+ **Scenario**: Show the core workflow — pulling ruff config from an upstream repo.
148
+
149
+ **Demonstrates**: The primary use case, colorful terminal output, speed of the tool.
150
+
151
+ **Where it goes**: `README.md` hero section, `docs/index.md`, `docs/usage.md`
152
+
153
+ ```tape
154
+ # tapes/pull_basic.tape
155
+ # Demonstrates: Basic ruff-sync pull from an upstream repository.
156
+
157
+ Source tapes/_common.tape
158
+
159
+ Require ruff-sync
160
+
161
+ Output docs/assets/recordings/pull_basic.gif
162
+
163
+ # Show the current state of pyproject.toml
164
+ Type "cat pyproject.toml | head -20"
165
+ Enter
166
+ Sleep 1.5s
167
+
168
+ # Run ruff-sync against the upstream
169
+ Type "ruff-sync https://github.com/Kilo59/ruff-sync -v"
170
+ Enter
171
+ Sleep 4s
172
+
173
+ # Show what changed
174
+ Type "git diff pyproject.toml | head -30"
175
+ Enter
176
+ Sleep 3s
177
+
178
+ # Clean up
179
+ Hide
180
+ Type "git checkout pyproject.toml"
181
+ Enter
182
+ Sleep 500ms
183
+ Show
184
+
185
+ Sleep 1s
186
+ ```
187
+
188
+ ---
189
+
190
+ ### Tape 2: `tapes/check_drift.tape` — Detecting Configuration Drift
191
+
192
+ **Scenario**: Show `ruff-sync check` detecting drift, displaying a diff, and exiting non-zero.
193
+
194
+ **Demonstrates**: CI use case, colored diff output, exit code behavior.
195
+
196
+ **Where it goes**: `docs/usage.md` (Checking for Drift section), `docs/ci-integration.md`, `README.md` (CI section)
197
+
198
+ > [!IMPORTANT]
199
+ > This tape requires the local `pyproject.toml` to be intentionally out of sync with the upstream to produce a diff. The setup steps below use a temporary modification that is hidden from the recording.
200
+
201
+ ```tape
202
+ # tapes/check_drift.tape
203
+ # Demonstrates: Catching configuration drift with `ruff-sync check`.
204
+
205
+ Source tapes/_common.tape
206
+
207
+ Require ruff-sync
208
+
209
+ Output docs/assets/recordings/check_drift.gif
210
+
211
+ # Silently introduce drift so the check fails
212
+ Hide
213
+ Type "cp pyproject.toml pyproject.toml.bak"
214
+ Enter
215
+ Sleep 300ms
216
+ # Remove a rule to simulate drift
217
+ Type `python3 -c "
218
+ t = open('pyproject.toml').read()
219
+ t = t.replace('\"PERF\",\n', '')
220
+ open('pyproject.toml', 'w').write(t)
221
+ "`
222
+ Enter
223
+ Sleep 500ms
224
+ Show
225
+
226
+ # Run the check command
227
+ Type "ruff-sync check --semantic -v"
228
+ Enter
229
+ Sleep 4s
230
+
231
+ # Show the exit code
232
+ Type "echo \"Exit code: $?\""
233
+ Enter
234
+ Sleep 2s
235
+
236
+ # Restore the original file (hidden)
237
+ Hide
238
+ Type "mv pyproject.toml.bak pyproject.toml"
239
+ Enter
240
+ Sleep 300ms
241
+ Show
242
+
243
+ Sleep 1s
244
+ ```
245
+
246
+ ---
247
+
248
+ ### Tape 3: `tapes/init_project.tape` — Bootstrapping a New Project
249
+
250
+ **Scenario**: Show `ruff-sync --init` scaffolding a brand-new `pyproject.toml` in an empty directory.
251
+
252
+ **Demonstrates**: Zero-config bootstrapping, `--init` flag, the generated `[tool.ruff-sync]` section.
253
+
254
+ **Where it goes**: `docs/usage.md` (Initializing section), `docs/index.md` (Quick Start)
255
+
256
+ ```tape
257
+ # tapes/init_project.tape
258
+ # Demonstrates: Bootstrapping a new project with --init.
259
+
260
+ Source tapes/_common.tape
261
+
262
+ Require ruff-sync
263
+
264
+ Output docs/assets/recordings/init_project.gif
265
+
266
+ # Create and enter a fresh directory
267
+ Type "mkdir /tmp/my-new-project && cd /tmp/my-new-project"
268
+ Enter
269
+ Sleep 500ms
270
+
271
+ Type "ls -la"
272
+ Enter
273
+ Sleep 1s
274
+
275
+ # Initialize from an upstream
276
+ Type "ruff-sync https://github.com/Kilo59/ruff-sync --init -v"
277
+ Enter
278
+ Sleep 4s
279
+
280
+ # Show the generated file
281
+ Type "cat pyproject.toml"
282
+ Enter
283
+ Sleep 3s
284
+
285
+ # Clean up (hidden)
286
+ Hide
287
+ Type "cd - && rm -rf /tmp/my-new-project"
288
+ Enter
289
+ Sleep 300ms
290
+ Show
291
+
292
+ Sleep 1s
293
+ ```
294
+
295
+ ---
296
+
297
+ ### Tape 4: `tapes/check_in_sync.tape` — Config is In Sync
298
+
299
+ **Scenario**: Show `ruff-sync check` passing (exit 0) when config is already in sync.
300
+
301
+ **Demonstrates**: Happy-path CI result, green success output.
302
+
303
+ **Where it goes**: `docs/ci-integration.md`, `docs/usage.md`
304
+
305
+ ```tape
306
+ # tapes/check_in_sync.tape
307
+ # Demonstrates: Happy path — config is already in sync.
308
+
309
+ Source tapes/_common.tape
310
+
311
+ Require ruff-sync
312
+
313
+ Output docs/assets/recordings/check_in_sync.gif
314
+
315
+ # Run the check — should pass since we're dogfooding our own config
316
+ Type "ruff-sync check --semantic -v"
317
+ Enter
318
+ Sleep 4s
319
+
320
+ # Confirm exit code
321
+ Type "echo \"Exit code: $?\""
322
+ Enter
323
+ Sleep 2s
324
+
325
+ Sleep 1s
326
+ ```
327
+
328
+ ---
329
+
330
+ ### Tape 5: `tapes/validate_strict.tape` — Validation and Strict Mode
331
+
332
+ **Scenario**: Show `--validate` and `--strict` flags in action.
333
+
334
+ **Demonstrates**: Config validation, strict mode catching deprecated rules, error output.
335
+
336
+ **Where it goes**: `docs/usage.md` (Validating Before Writing section)
337
+
338
+ ```tape
339
+ # tapes/validate_strict.tape
340
+ # Demonstrates: --validate and --strict flags.
341
+
342
+ Source tapes/_common.tape
343
+
344
+ Require ruff-sync
345
+
346
+ Output docs/assets/recordings/validate_strict.gif
347
+
348
+ # First show normal validation passing
349
+ Type "ruff-sync --validate -v"
350
+ Enter
351
+ Sleep 4s
352
+
353
+ Type ""
354
+ Enter
355
+ Sleep 500ms
356
+
357
+ # Now show strict mode
358
+ Type "ruff-sync --strict -v"
359
+ Enter
360
+ Sleep 4s
361
+
362
+ Sleep 2s
363
+ ```
364
+
365
+ ---
366
+
367
+ ### Tape 6: `tapes/help_overview.tape` — Help Output
368
+
369
+ **Scenario**: Show the `--help` output for the tool and subcommands.
370
+
371
+ **Demonstrates**: Available commands, flags, general CLI structure.
372
+
373
+ **Where it goes**: `README.md`, `docs/usage.md` (Command Reference section)
374
+
375
+ ```tape
376
+ # tapes/help_overview.tape
377
+ # Demonstrates: CLI help output overview.
378
+
379
+ Source tapes/_common.tape
380
+
381
+ Require ruff-sync
382
+
383
+ Output docs/assets/recordings/help_overview.gif
384
+
385
+ Set Height 700
386
+
387
+ # Main help
388
+ Type "ruff-sync --help"
389
+ Enter
390
+ Sleep 3s
391
+
392
+ # Pull help
393
+ Type "ruff-sync pull --help"
394
+ Enter
395
+ Sleep 3s
396
+
397
+ # Check help
398
+ Type "ruff-sync check --help"
399
+ Enter
400
+ Sleep 3s
401
+
402
+ Sleep 1s
403
+ ```
404
+
405
+ ---
406
+
407
+ ## Invoke Task for Regeneration
408
+
409
+ Add a new Invoke task to `tasks.py` so recordings can be regenerated with a single command.
410
+
411
+ ### Task definition
412
+
413
+ Add the following task to `tasks.py`:
414
+
415
+ ```python
416
+ @task(
417
+ help={
418
+ "tape": "Specific tape file to record (e.g. 'pull_basic'). Default: all tapes.",
419
+ },
420
+ )
421
+ def recordings(ctx, tape=None):
422
+ """Regenerate CLI animation GIFs from VHS tape files."""
423
+ import pathlib
424
+
425
+ tapes_dir = pathlib.Path("tapes")
426
+ if not tapes_dir.exists():
427
+ print("❌ tapes/ directory not found. Run from the project root.")
428
+ raise SystemExit(1)
429
+
430
+ # Check VHS is installed
431
+ result = ctx.run("which vhs", hide=True, warn=True)
432
+ if not result.ok:
433
+ print("❌ VHS is not installed. Install with: brew install vhs")
434
+ raise SystemExit(1)
435
+
436
+ if tape:
437
+ tape_file = tapes_dir / f"{tape}.tape"
438
+ if not tape_file.exists():
439
+ print(f"❌ Tape file not found: {tape_file}")
440
+ raise SystemExit(1)
441
+ tape_files = [tape_file]
442
+ else:
443
+ # Process all tape files except _common.tape
444
+ tape_files = sorted(
445
+ f for f in tapes_dir.glob("*.tape") if not f.name.startswith("_")
446
+ )
447
+
448
+ if not tape_files:
449
+ print("⚠️ No tape files found in tapes/")
450
+ return
451
+
452
+ print(f"🎬 Recording {len(tape_files)} tape(s)...")
453
+ for tf in tape_files:
454
+ print(f" 📼 {tf.name}")
455
+ ctx.run(f"vhs {tf}")
456
+
457
+ print("\n🎉 All recordings complete!")
458
+ print(" Output: docs/assets/recordings/")
459
+ ```
460
+
461
+ ### Register the task alias
462
+
463
+ In the Invoke `ns` (namespace) collection at the bottom of `tasks.py`, add:
464
+
465
+ ```python
466
+ ns.add_task(recordings)
467
+ ```
468
+
469
+ ### Usage
470
+
471
+ ```bash
472
+ # Regenerate all recordings
473
+ uv run invoke recordings
474
+
475
+ # Regenerate a specific recording
476
+ uv run invoke recordings --tape pull_basic
477
+ ```
478
+
479
+ ---
480
+
481
+ ## Documentation Integration
482
+
483
+ ### README.md
484
+
485
+ Add the hero GIF right after the banner image (line ~2):
486
+
487
+ ```markdown
488
+ <p align="center">
489
+ <img src="https://raw.githubusercontent.com/Kilo59/ruff-sync/main/docs/assets/ruff_sync_banner.png" alt="ruff-sync banner" style="max-width: 600px; width: 100%; height: auto; margin-bottom: 1rem;">
490
+ <br>
491
+ <img src="https://raw.githubusercontent.com/Kilo59/ruff-sync/main/docs/assets/recordings/pull_basic.gif" alt="ruff-sync pull demo" style="max-width: 600px; width: 100%; height: auto;">
492
+ <br>
493
+ <!-- badges -->
494
+ ```
495
+
496
+ Add the check drift animation in the CI Integration section (~line 287):
497
+
498
+ ```markdown
499
+ ## CI Integration
500
+
501
+ ![ruff-sync check detecting drift](docs/assets/recordings/check_drift.gif)
502
+ ```
503
+
504
+ ### docs/index.md
505
+
506
+ Add the hero GIF after the banner:
507
+
508
+ ```markdown
509
+ ![ruff-sync banner](assets/ruff_sync_banner.png)
510
+
511
+ ![ruff-sync pull demo](assets/recordings/pull_basic.gif)
512
+ ```
513
+
514
+ Add the init GIF in the Quick Start section:
515
+
516
+ ```markdown
517
+ ### 1. Initialize a new project (Optional)
518
+
519
+ ![Bootstrapping a new project with --init](assets/recordings/init_project.gif)
520
+ ```
521
+
522
+ ### docs/usage.md
523
+
524
+ Add animations inline with each section:
525
+
526
+ 1. **The Basic Sync** → `pull_basic.gif`
527
+ 2. **Checking for Drift** → `check_drift.gif`
528
+ 3. **Validating Before Writing** → `validate_strict.gif`
529
+
530
+ Example:
531
+
532
+ ```markdown
533
+ ## 🌟 Common Workflows
534
+
535
+ ### The Basic Sync
536
+
537
+ ![Basic ruff-sync pull](assets/recordings/pull_basic.gif)
538
+
539
+ If you want to pull rules from a central repository...
540
+ ```
541
+
542
+ ### docs/ci-integration.md
543
+
544
+ Add the check animations:
545
+
546
+ ```markdown
547
+ ![Config in sync](assets/recordings/check_in_sync.gif)
548
+
549
+ ![Config drift detected](assets/recordings/check_drift.gif)
550
+ ```
551
+
552
+ ---
553
+
554
+ ## Agent Workflow for Updating Recordings
555
+
556
+ Create a new workflow file at `.agents/workflows/update-recordings.md`:
557
+
558
+ ```markdown
559
+ ---
560
+ description: Regenerate CLI animation GIFs for documentation
561
+ ---
562
+
563
+ Use this workflow to update the CLI animation GIFs when commands, output formatting, or CLI behavior changes.
564
+
565
+ ### 1. Prerequisites
566
+ // turbo
567
+ 1. Verify VHS is installed:
568
+ ```bash
569
+ which vhs && vhs --version
570
+ ```
571
+ If not installed: `brew install vhs`
572
+
573
+ ### 2. Regenerate All Recordings
574
+ // turbo
575
+ 1. Run the Invoke task:
576
+ ```bash
577
+ uv run invoke recordings
578
+ ```
579
+ *This processes all `.tape` files in `tapes/` and outputs GIFs to `docs/assets/recordings/`.*
580
+
581
+ ### 3. Regenerate a Single Recording
582
+ // turbo
583
+ 1. To regenerate only one:
584
+ ```bash
585
+ uv run invoke recordings --tape pull_basic
586
+ ```
587
+
588
+ ### 4. Verify Output
589
+ 1. Check the `docs/assets/recordings/` directory for updated `.gif` files.
590
+ 2. Open each GIF to verify it looks correct and the terminal output is legible.
591
+
592
+ ### 5. Commit Changes
593
+ 1. Stage and commit:
594
+ ```bash
595
+ git add docs/assets/recordings/*.gif tapes/*.tape
596
+ git commit -m "docs: update CLI animation recordings"
597
+ ```
598
+
599
+ ---
600
+
601
+ ### Adding a New Recording
602
+
603
+ 1. **Create a new tape file** in `tapes/` (e.g., `tapes/my_feature.tape`).
604
+ 2. **Start with** `Source tapes/_common.tape` to inherit shared settings.
605
+ 3. **Set the output** path: `Output docs/assets/recordings/my_feature.gif`
606
+ 4. **Add the commands** using VHS syntax (`Type`, `Enter`, `Sleep`, etc.).
607
+ 5. **Test it**: `vhs tapes/my_feature.tape`
608
+ 6. **Embed** the GIF in the relevant docs markdown file.
609
+
610
+ ### Editing an Existing Recording
611
+
612
+ 1. Edit the `.tape` file in `tapes/`.
613
+ 2. Run `uv run invoke recordings --tape <name>` to regenerate just that GIF.
614
+ 3. Review the output GIF.
615
+
616
+ ### VHS Quick Reference (for agents)
617
+
618
+ | Command | Example | What it does |
619
+ |---|---|---|
620
+ | `Source` | `Source tapes/_common.tape` | Include settings from another tape |
621
+ | `Output` | `Output out.gif` | Set output file path and format |
622
+ | `Require` | `Require ruff-sync` | Fail fast if a program is missing |
623
+ | `Set` | `Set FontSize 16` | Configure terminal settings |
624
+ | `Type` | `Type "ruff-sync --help"` | Type characters into the terminal |
625
+ | `Enter` | `Enter` | Press the Enter key |
626
+ | `Sleep` | `Sleep 2s` | Wait for a specified duration |
627
+ | `Hide` | `Hide` | Stop recording (for setup commands) |
628
+ | `Show` | `Show` | Resume recording |
629
+ | `Ctrl+c` | `Ctrl+C` | Send Ctrl+C |
630
+ ```
631
+
632
+ ---
633
+
634
+ ## Optional: CI Workflow for Recording Validation
635
+
636
+ Add a GitHub Actions workflow that validates tape files (but doesn't regenerate GIFs) on every PR that touches `tapes/`:
637
+
638
+ ```yaml
639
+ # .github/workflows/validate-tapes.yaml
640
+ name: Validate VHS Tapes
641
+
642
+ on:
643
+ pull_request:
644
+ paths:
645
+ - "tapes/**"
646
+
647
+ jobs:
648
+ validate:
649
+ runs-on: ubuntu-latest
650
+ steps:
651
+ - uses: actions/checkout@v4
652
+ - name: Install VHS
653
+ run: |
654
+ sudo mkdir -p /etc/apt/keyrings
655
+ curl -fsSL https://repo.charm.sh/apt/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/charm.gpg
656
+ echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | sudo tee /etc/apt/sources.list.d/charm.list
657
+ sudo apt update && sudo apt install -y vhs
658
+ - name: Validate tape files
659
+ run: |
660
+ for tape in tapes/*.tape; do
661
+ if [[ "$(basename "$tape")" == _* ]]; then continue; fi
662
+ echo "Validating $tape..."
663
+ vhs validate "$tape"
664
+ done
665
+ ```
666
+
667
+ > [!TIP]
668
+ > Full GIF regeneration can be done manually or in a separate CI job since it's slow and requires `ttyd` + `ffmpeg`. The validation-only step is fast and catches syntax errors early.
669
+
670
+ ---
671
+
672
+ ## Execution Checklist
673
+
674
+ | # | Step | Command / Action |
675
+ |---|---|---|
676
+ | 1 | Install VHS | `brew install vhs` |
677
+ | 2 | Create directories | `mkdir -p docs/assets/recordings tapes` |
678
+ | 3 | Create `tapes/_common.tape` | Copy from [Shared Settings](#shared-settings-tapes_commontape) above |
679
+ | 4 | Create all 6 tape files | Copy from [Tape Files](#tape-files) section above |
680
+ | 5 | Test one tape | `vhs tapes/help_overview.tape` (fastest, no side effects) |
681
+ | 6 | Add Invoke task to `tasks.py` | Copy from [Invoke Task](#invoke-task-for-regeneration) above |
682
+ | 7 | Generate all recordings | `uv run invoke recordings` |
683
+ | 8 | Review all GIFs | Open `docs/assets/recordings/*.gif` |
684
+ | 9 | Integrate into README.md | Follow [README.md](#readmemd) integration instructions |
685
+ | 10 | Integrate into MkDocs pages | Follow [docs/ integration](#documentation-integration) instructions |
686
+ | 11 | Create agent workflow | Copy to `.agents/workflows/update-recordings.md` |
687
+ | 12 | (Optional) Add CI validation | Copy [CI workflow](#optional-ci-workflow-for-recording-validation) to `.github/workflows/` |
688
+ | 13 | Commit everything | `git add tapes/ docs/assets/recordings/ .agents/workflows/update-recordings.md` |
689
+
690
+ ---
691
+
692
+ ## Notes for the Implementing Agent
693
+
694
+ 1. **Run tapes from the project root.** VHS will execute commands in the current working directory. Tape files reference relative paths like `tapes/_common.tape`.
695
+
696
+ 2. **The `check_drift.tape` needs intentional drift.** It uses `Hide`/`Show` to silently modify `pyproject.toml` before running the check, then restores it. The implementing agent must ensure the Python one-liner in the tape actually removes a rule that exists in the current file.
697
+
698
+ 3. **Font availability.** The `JetBrains Mono` font is specified in `_common.tape`. If not installed on the system, VHS will fall back to a default monospace font. For consistent results, install it: `brew install --cask font-jetbrains-mono`.
699
+
700
+ 4. **Timing tuning.** The `Sleep` durations in each tape are estimates. After generating, review the GIFs and adjust:
701
+ - Increase `Sleep` if output is cut off
702
+ - Decrease `Sleep` if there's too much dead time
703
+ - Adjust `TypingSpeed` in `_common.tape` for faster/slower typing animation
704
+
705
+ 5. **Theme choice.** `Catppuccin Mocha` was chosen to match the dark-mode aesthetic of the MkDocs Material theme. If the project switches to a light theme, change to `Catppuccin Latte` or `One Light` in `_common.tape`.
706
+
707
+ 6. **GIF file sizes.** Target under 500 KB per GIF. If a recording is too large:
708
+ - Reduce the terminal `Width`/`Height`
709
+ - Shorten `Sleep` durations
710
+ - Reduce the amount of output shown (pipe through `head`)