jj-stack 0.1.0__tar.gz → 0.1.2__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 (232) hide show
  1. {jj_stack-0.1.0 → jj_stack-0.1.2}/.github/workflows/ci.yml +3 -3
  2. {jj_stack-0.1.0 → jj_stack-0.1.2}/.github/workflows/codeql.yml +2 -2
  3. {jj_stack-0.1.0 → jj_stack-0.1.2}/.github/workflows/release.yml +55 -15
  4. {jj_stack-0.1.0 → jj_stack-0.1.2}/AGENTS.md +13 -22
  5. {jj_stack-0.1.0 → jj_stack-0.1.2}/PKG-INFO +39 -11
  6. {jj_stack-0.1.0 → jj_stack-0.1.2}/README.md +36 -10
  7. {jj_stack-0.1.0 → jj_stack-0.1.2}/check.py +10 -2
  8. {jj_stack-0.1.0 → jj_stack-0.1.2}/complexity-budget.toml +1 -0
  9. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/README.md +2 -1
  10. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/guides/continue-a-stack.md +4 -4
  11. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/guides/merge-and-sync.md +11 -11
  12. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/guides/review-a-stack.md +9 -3
  13. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/guides/submit-and-update.md +7 -0
  14. jj_stack-0.1.2/docs/guides/working-on-github.md +55 -0
  15. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/internals/code-reviews.md +2 -2
  16. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/internals/design.md +39 -19
  17. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/internals/implementation-strategy.md +13 -0
  18. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/internals/property-testing.md +2 -2
  19. jj_stack-0.1.2/docs/internals/releasing.md +71 -0
  20. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/json-output.schema.json +8 -0
  21. jj_stack-0.1.2/docs/quick-start.md +131 -0
  22. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/reference/automation.md +6 -6
  23. jj_stack-0.1.2/docs/reference/bookmarks-and-selection.md +149 -0
  24. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/reference/commands.md +4 -1
  25. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/reference/configuration.md +10 -1
  26. jj_stack-0.1.2/docs/reference/descriptions.md +84 -0
  27. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/reference/json-output.md +15 -8
  28. jj_stack-0.1.2/docs/tool-comparison.md +215 -0
  29. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/troubleshooting.md +0 -7
  30. jj_stack-0.1.2/justfile +60 -0
  31. {jj_stack-0.1.0 → jj_stack-0.1.2}/pyproject.toml +10 -5
  32. jj_stack-0.1.2/release-notes/v0.1.2.md +34 -0
  33. {jj_stack-0.1.0 → jj_stack-0.1.2}/skills/jj-stack/SKILL.md +15 -4
  34. {jj_stack-0.1.0 → jj_stack-0.1.2}/skills/jj-stack/references/recovery.md +13 -9
  35. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/cli.py +9 -5
  36. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/_cleanup_actions.py +34 -92
  37. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/_json_status.py +1 -0
  38. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/checkout.py +39 -38
  39. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/cleanup/command.py +108 -149
  40. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/list_.py +79 -51
  41. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/merge/command.py +31 -27
  42. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/merge/github_stack.py +26 -7
  43. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/merge/models.py +2 -3
  44. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/merge/plan.py +0 -1
  45. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/merge/preconditions.py +17 -22
  46. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/relink.py +49 -31
  47. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/submit/auto_close.py +3 -1
  48. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/submit/command.py +199 -86
  49. jj_stack-0.1.2/src/jj_stack/commands/submit/comments.py +62 -0
  50. jj_stack-0.1.2/src/jj_stack/commands/submit/default_pr_text.py +54 -0
  51. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/submit/descriptions.py +118 -25
  52. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/submit/github_stack.py +47 -4
  53. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/submit/inputs.py +49 -0
  54. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/submit/models.py +5 -2
  55. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/submit/overview_comments.py +74 -63
  56. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/submit/prs.py +27 -39
  57. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/submit/render.py +12 -6
  58. jj_stack-0.1.2/src/jj_stack/commands/submit/revision_comments.py +166 -0
  59. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/sync.py +13 -11
  60. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/sync_apply.py +16 -6
  61. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/unstack.py +6 -6
  62. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/view.py +83 -47
  63. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/completion.py +1 -1
  64. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/console.py +15 -2
  65. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/errors.py +4 -0
  66. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/formatting.py +47 -8
  67. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/github/client.py +476 -94
  68. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/github/overview_comments.py +0 -6
  69. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/github/resolution.py +0 -6
  70. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/jj/client.py +23 -50
  71. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/models/github.py +37 -0
  72. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/models/tracking.py +5 -27
  73. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/stack/change_status.py +7 -0
  74. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/stack/convergence.py +17 -30
  75. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/stack/convergence_observation.py +5 -15
  76. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/stack/github_stack_safety.py +11 -19
  77. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/stack/global_convergence.py +13 -18
  78. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/stack/path.py +0 -2
  79. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/stack/pr_branches.py +1 -4
  80. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/stack/pr_facts.py +36 -34
  81. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/stack/repo.py +4 -4
  82. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/stack/selected.py +13 -7
  83. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/stack/selection.py +27 -12
  84. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/stack/status.py +16 -62
  85. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/stack/trunk_evidence.py +11 -15
  86. jj_stack-0.1.2/src/jj_stack/state/migrations.py +63 -0
  87. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/state/store.py +6 -32
  88. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/ui.py +23 -1
  89. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/integration/submit_command_helpers.py +0 -57
  90. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/integration/test_boundary_conditions.py +0 -8
  91. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/integration/test_cleanup_command.py +19 -60
  92. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/integration/test_doctor_command.py +8 -20
  93. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/integration/test_jj_stack.py +46 -25
  94. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/integration/test_list_command.py +19 -10
  95. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/integration/test_relink_command.py +19 -11
  96. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/integration/test_submit_command.py +228 -42
  97. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/integration/test_sync_command.py +6 -4
  98. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/integration/test_view_command.py +9 -9
  99. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/property/test_submit_property_scenarios.py +16 -31
  100. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/run_submit_property_scenarios.py +2 -2
  101. jj_stack-0.1.2/tests/support/contexts.py +49 -0
  102. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/support/fake_github.py +117 -15
  103. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/support/integration_helpers.py +87 -42
  104. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/support/submit_property_harness.py +13 -25
  105. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/support/submit_property_scenarios.py +100 -45
  106. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/support/tracking.py +0 -6
  107. jj_stack-0.1.2/tests/unit/conftest.py +14 -0
  108. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_change_status.py +5 -15
  109. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_change_status_topology.py +10 -20
  110. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_check_script.py +13 -0
  111. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_cleanup.py +14 -41
  112. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_cli.py +1 -4
  113. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_cli_dispatch.py +1 -4
  114. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_completion.py +3 -0
  115. jj_stack-0.1.2/tests/unit/test_default_pr_text.py +56 -0
  116. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_github_client.py +177 -24
  117. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_github_models.py +27 -5
  118. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_github_stack_planning.py +35 -3
  119. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_in_use_command.py +1 -4
  120. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_jj_client.py +25 -150
  121. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_pr_branches.py +3 -24
  122. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_relink.py +10 -14
  123. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_stack_status.py +22 -132
  124. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_store.py +84 -19
  125. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_submit.py +41 -44
  126. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_submit_descriptions.py +19 -2
  127. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_trunk_evidence.py +4 -19
  128. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_ui.py +24 -0
  129. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_view.py +146 -116
  130. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_view_entrypoint.py +10 -3
  131. {jj_stack-0.1.0 → jj_stack-0.1.2}/uv.lock +44 -42
  132. jj_stack-0.1.0/docs/gh-stack.md +0 -38
  133. jj_stack-0.1.0/docs/guides/working-on-github.md +0 -52
  134. jj_stack-0.1.0/docs/internals/releasing.md +0 -47
  135. jj_stack-0.1.0/docs/quick-start.md +0 -91
  136. jj_stack-0.1.0/docs/reference/descriptions.md +0 -59
  137. jj_stack-0.1.0/tests/unit/entrypoint_test_helpers.py +0 -37
  138. {jj_stack-0.1.0 → jj_stack-0.1.2}/.github/SECURITY.md +0 -0
  139. {jj_stack-0.1.0 → jj_stack-0.1.2}/.github/dependabot.yml +0 -0
  140. {jj_stack-0.1.0 → jj_stack-0.1.2}/.github/workflows/block-pr-base-merges.yml +0 -0
  141. {jj_stack-0.1.0 → jj_stack-0.1.2}/.github/workflows/check-jj-release-updates.yml +0 -0
  142. {jj_stack-0.1.0 → jj_stack-0.1.2}/.gitignore +0 -0
  143. {jj_stack-0.1.0 → jj_stack-0.1.2}/CLAUDE.md +0 -0
  144. {jj_stack-0.1.0 → jj_stack-0.1.2}/LICENSE +0 -0
  145. {jj_stack-0.1.0 → jj_stack-0.1.2}/NOTICE +0 -0
  146. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/AGENTS.md +0 -0
  147. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/guides/close-or-separate.md +0 -0
  148. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/guides/multiple-stacks.md +0 -0
  149. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/guides/revise.md +0 -0
  150. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/internals/AGENTS.md +0 -0
  151. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/internals/README.md +0 -0
  152. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/internals/testing-philosophy.md +0 -0
  153. {jj_stack-0.1.0 → jj_stack-0.1.2}/docs/mental-model.md +0 -0
  154. {jj_stack-0.1.0 → jj_stack-0.1.2}/evals/jj-stack-skill.md +0 -0
  155. {jj_stack-0.1.0 → jj_stack-0.1.2}/scripts/README.md +0 -0
  156. {jj_stack-0.1.0 → jj_stack-0.1.2}/scripts/describe_with_claude.py +0 -0
  157. {jj_stack-0.1.0 → jj_stack-0.1.2}/scripts/describe_with_codex.py +0 -0
  158. {jj_stack-0.1.0 → jj_stack-0.1.2}/scripts/describe_with_editor.py +0 -0
  159. {jj_stack-0.1.0 → jj_stack-0.1.2}/scripts/describe_with_prompt.py +0 -0
  160. {jj_stack-0.1.0 → jj_stack-0.1.2}/skills/jj-stack/agents/openai.yaml +0 -0
  161. {jj_stack-0.1.0 → jj_stack-0.1.2}/skills/jj-stack/references/multi-stack.md +0 -0
  162. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/__init__.py +0 -0
  163. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/__main__.py +0 -0
  164. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/bootstrap.py +0 -0
  165. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/cli_help.py +0 -0
  166. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/__init__.py +0 -0
  167. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/cleanup/shared.py +0 -0
  168. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/cleanup/stale.py +0 -0
  169. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/doctor.py +0 -0
  170. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/in_use.py +0 -0
  171. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/merge/__init__.py +0 -0
  172. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/merge/render.py +0 -0
  173. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/submit/__init__.py +0 -0
  174. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/commands/submit/changes.py +0 -0
  175. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/concurrency.py +0 -0
  176. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/config.py +0 -0
  177. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/github/__init__.py +0 -0
  178. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/github/auth.py +0 -0
  179. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/github/error_messages.py +0 -0
  180. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/github/pr_refs.py +0 -0
  181. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/github/stack_availability.py +0 -0
  182. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/identifiers.py +0 -0
  183. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/jj/__init__.py +0 -0
  184. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/jj/cli_args.py +0 -0
  185. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/jj/colors.py +0 -0
  186. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/models/__init__.py +0 -0
  187. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/models/git.py +0 -0
  188. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/models/stack.py +0 -0
  189. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/pr_branch_namespace.py +0 -0
  190. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/stack/__init__.py +0 -0
  191. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/stack/convergence_models.py +0 -0
  192. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/state/__init__.py +0 -0
  193. {jj_stack-0.1.0 → jj_stack-0.1.2}/src/jj_stack/state/operation_lock.py +0 -0
  194. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/__init__.py +0 -0
  195. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/conftest.py +0 -0
  196. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/integration/__init__.py +0 -0
  197. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/integration/conftest.py +0 -0
  198. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/integration/test_checkout_command.py +0 -0
  199. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/integration/test_merge_command.py +1 -1
  200. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/integration/test_unstack_command.py +1 -1
  201. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/run_live_github.py +0 -0
  202. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/support/__init__.py +0 -0
  203. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/support/change_helpers.py +0 -0
  204. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/support/json_schema.py +0 -0
  205. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/support/output_assertions.py +0 -0
  206. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/support/pytest_concurrency.py +0 -0
  207. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/support/stack_edit_scenarios.py +0 -0
  208. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/__init__.py +0 -0
  209. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_bootstrap.py +0 -0
  210. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_checkout.py +0 -0
  211. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_concurrency.py +0 -0
  212. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_config.py +0 -0
  213. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_describe_with_editor_script.py +0 -0
  214. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_describe_with_prompt_script.py +0 -0
  215. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_errors.py +0 -0
  216. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_github_auth.py +0 -0
  217. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_github_resolution.py +0 -0
  218. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_list.py +0 -0
  219. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_live_github_runner.py +0 -0
  220. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_merge.py +0 -0
  221. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_operation_lock.py +0 -0
  222. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_pr_refs.py +0 -0
  223. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_property_runner.py +0 -0
  224. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_property_scenarios.py +0 -0
  225. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_selection.py +0 -0
  226. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_stack_path.py +0 -0
  227. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_sync.py +0 -0
  228. {jj_stack-0.1.0 → jj_stack-0.1.2}/tests/unit/test_unstack.py +0 -0
  229. {jj_stack-0.1.0 → jj_stack-0.1.2}/tools/check_complexity.py +0 -0
  230. {jj_stack-0.1.0 → jj_stack-0.1.2}/tools/check_jj_release_updates.py +0 -0
  231. {jj_stack-0.1.0 → jj_stack-0.1.2}/tools/check_release_artifacts.py +0 -0
  232. {jj_stack-0.1.0 → jj_stack-0.1.2}/tools/install-jj-release.sh +0 -0
@@ -18,7 +18,7 @@ jobs:
18
18
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
19
19
 
20
20
  - name: Set up uv
21
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
21
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
22
22
  with:
23
23
  python-version: "3.14"
24
24
 
@@ -51,7 +51,7 @@ jobs:
51
51
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
52
52
 
53
53
  - name: Set up uv
54
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
54
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
55
55
  with:
56
56
  python-version: ${{ matrix.python-version }}
57
57
 
@@ -78,7 +78,7 @@ jobs:
78
78
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
79
79
 
80
80
  - name: Set up uv
81
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
81
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
82
82
  with:
83
83
  python-version: "3.14"
84
84
 
@@ -23,10 +23,10 @@ jobs:
23
23
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
24
24
 
25
25
  - name: Initialize CodeQL
26
- uses: github/codeql-action/init@v4.37.3
26
+ uses: github/codeql-action/init@v4.37.7
27
27
  with:
28
28
  languages: python
29
29
  build-mode: none
30
30
 
31
31
  - name: Analyze
32
- uses: github/codeql-action/analyze@v4.37.3
32
+ uses: github/codeql-action/analyze@v4.37.7
@@ -5,6 +5,11 @@ on:
5
5
  tags:
6
6
  - "v*"
7
7
  workflow_dispatch:
8
+ inputs:
9
+ release_tag:
10
+ description: Existing tag to publish to production; leave empty for TestPyPI
11
+ required: false
12
+ type: string
8
13
 
9
14
  permissions:
10
15
  contents: read
@@ -26,22 +31,36 @@ jobs:
26
31
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
27
32
  with:
28
33
  fetch-depth: 0
34
+ ref: ${{ inputs.release_tag || github.ref }}
29
35
 
30
36
  - name: Set up uv
31
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
37
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
32
38
  with:
33
39
  python-version: "3.14"
34
40
 
35
41
  - name: Verify tag matches package version
36
- if: startsWith(github.ref, 'refs/tags/v')
42
+ if: github.event_name == 'push' || inputs.release_tag != ''
37
43
  env:
38
- RELEASE_TAG: ${{ github.ref_name }}
39
- run: test "$RELEASE_TAG" = "v$(uv version --short)"
44
+ RELEASE_TAG: ${{ inputs.release_tag || github.ref_name }}
45
+ run: |
46
+ test "$RELEASE_TAG" = "v$(uv version --short)"
47
+ test "$(git rev-parse HEAD)" = "$(git rev-parse "refs/tags/$RELEASE_TAG^{commit}")"
40
48
 
41
49
  - name: Verify tagged commit is on main
42
- if: startsWith(github.ref, 'refs/tags/v')
50
+ if: github.event_name == 'push' || inputs.release_tag != ''
43
51
  run: git merge-base --is-ancestor HEAD refs/remotes/origin/main
44
52
 
53
+ - name: Verify release notes
54
+ if: github.event_name == 'push' || inputs.release_tag != ''
55
+ env:
56
+ RELEASE_TAG: ${{ inputs.release_tag || github.ref_name }}
57
+ run: |
58
+ release_notes="release-notes/$RELEASE_TAG.md"
59
+ if ! test -s "$release_notes"; then
60
+ echo "::error file=$release_notes::Add human-written release notes for $RELEASE_TAG"
61
+ exit 1
62
+ fi
63
+
45
64
  - name: Install jj
46
65
  run: echo "$(tools/install-jj-release.sh "$JJ_VERSION")" >> "$GITHUB_PATH"
47
66
 
@@ -52,7 +71,7 @@ jobs:
52
71
  run: uv build
53
72
 
54
73
  - name: Test built distributions
55
- run: python tools/check_release_artifacts.py
74
+ run: uv run --no-project --python 3.14 python tools/check_release_artifacts.py
56
75
 
57
76
  - name: Upload distributions
58
77
  uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
@@ -63,7 +82,7 @@ jobs:
63
82
  retention-days: 7
64
83
 
65
84
  publish-testpypi:
66
- if: github.event_name == 'workflow_dispatch'
85
+ if: github.event_name == 'workflow_dispatch' && inputs.release_tag == ''
67
86
  needs: build
68
87
  runs-on: ubuntu-latest
69
88
  timeout-minutes: 10
@@ -75,7 +94,7 @@ jobs:
75
94
 
76
95
  steps:
77
96
  - name: Set up uv
78
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
97
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
79
98
  with:
80
99
  python-version: "3.14"
81
100
 
@@ -94,7 +113,9 @@ jobs:
94
113
  dist/*
95
114
 
96
115
  publish-pypi:
97
- if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
116
+ if: >-
117
+ (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) ||
118
+ (github.event_name == 'workflow_dispatch' && inputs.release_tag != '')
98
119
  needs: build
99
120
  runs-on: ubuntu-latest
100
121
  timeout-minutes: 10
@@ -106,7 +127,7 @@ jobs:
106
127
 
107
128
  steps:
108
129
  - name: Set up uv
109
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
130
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
110
131
  with:
111
132
  python-version: "3.14"
112
133
 
@@ -131,6 +152,11 @@ jobs:
131
152
  contents: write
132
153
 
133
154
  steps:
155
+ - name: Check out release
156
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
157
+ with:
158
+ ref: ${{ inputs.release_tag || github.ref }}
159
+
134
160
  - name: Download distributions
135
161
  uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
136
162
  with:
@@ -140,10 +166,24 @@ jobs:
140
166
  - name: Publish GitHub release
141
167
  env:
142
168
  GH_TOKEN: ${{ github.token }}
143
- RELEASE_TAG: ${{ github.ref_name }}
169
+ RELEASE_TAG: ${{ inputs.release_tag || github.ref_name }}
144
170
  run: |
145
- if ! gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
146
- gh release create "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" --verify-tag \
147
- --generate-notes --title "$RELEASE_TAG"
171
+ release_notes="release-notes/$RELEASE_TAG.md"
172
+ if gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
173
+ expected_notes="$(cat "$release_notes")"
174
+ published_notes="$(
175
+ gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" \
176
+ --json body --jq .body
177
+ )"
178
+ if test "$published_notes" != "$expected_notes"; then
179
+ echo "::error file=$release_notes::Published notes do not match $release_notes"
180
+ exit 1
181
+ fi
182
+ for artifact in dist/*; do
183
+ gh release verify-asset "$RELEASE_TAG" "$artifact" \
184
+ --repo "$GITHUB_REPOSITORY"
185
+ done
186
+ else
187
+ gh release create "$RELEASE_TAG" dist/* --repo "$GITHUB_REPOSITORY" \
188
+ --verify-tag --notes-file "$release_notes" --title "$RELEASE_TAG"
148
189
  fi
149
- gh release upload "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" --clobber dist/*
@@ -1,8 +1,3 @@
1
- # Work in progress
2
-
3
- This project is under heavy development. Do not make any attempt to write backwards
4
- compatibility code, migration code, or the like.
5
-
6
1
  ## Complexity control
7
2
 
8
3
  - A replacement is incomplete until it deletes the mechanism it supersedes in the same change.
@@ -13,10 +8,9 @@ compatibility code, migration code, or the like.
13
8
  external mutation to the identity and version observed while planning when the platform
14
9
  supports a conditional write or lease. Re-observe only when an earlier mutation invalidates a
15
10
  precondition or when an observed trigger or platform contract requires it.
16
- - Apply the cumulative complexity budgets after every code slice. CI runs
17
- `uv run tools/check_complexity.py`; run it locally when the pinned `tokei` is installed. A
18
- budget increase is a design stop that requires explicit review, not routine maintenance of the
19
- budget file.
11
+ - Apply the cumulative complexity budgets after every code slice. Run `just complexity` locally
12
+ when the pinned `tokei` is installed; CI invokes the underlying checker. A budget increase is a
13
+ design stop that requires explicit review, not routine maintenance of the budget file.
20
14
  - If the same subsystem needs a third consecutive hardening change, stop patching it and
21
15
  re-derive the design from the core invariants.
22
16
 
@@ -25,8 +19,8 @@ compatibility code, migration code, or the like.
25
19
  - This is a `jj` repo. Do not use `git` to work on the repo itself.
26
20
  - Do not use git worktree-based agent isolation in this repo. For isolated parallel work, use
27
21
  `jj workspace` instead.
28
- - Run the CLI locally with `uv run jj-stack ...` instead of invoking the module or virtualenv
29
- path directly.
22
+ - Run the CLI locally with `just run ...` instead of invoking the module or virtualenv path
23
+ directly.
30
24
  - Hard-wrap code and markdown files at 98 columns unless a file uses a different convention.
31
25
 
32
26
  # Commit messages
@@ -38,7 +32,7 @@ compatibility code, migration code, or the like.
38
32
  - Hard-wrap commit message bodies at 72 columns.
39
33
  - The body should explain the motivation for the change, the intended behavior or design outcome,
40
34
  and any important scope or design constraints.
41
- - Do not use the body to narrate the code or to record routine validation such as `./check.py`.
35
+ - Do not use the body to narrate the code or to record routine validation such as `just check`.
42
36
  - Prefer explaining why the commit exists and what rule or user-visible behavior it is enforcing.
43
37
 
44
38
  # Documentation
@@ -47,9 +41,10 @@ compatibility code, migration code, or the like.
47
41
  rules and the public/internal split. Built-in `--help` text is held to the same standard as
48
42
  the user docs: assume jj/git familiarity, avoid `jj-stack` internal design jargon.
49
43
  - The web version of the user docs normally lives in the sibling jj repository at
50
- `$(jj root)/../website`. When user-facing docs change here, inspect and update the corresponding
51
- web docs there too when needed. If the change here is committed, commit the corresponding
52
- website update in that repository as well; preserve unrelated work in either working copy.
44
+ `$(jj root)/../website`. When user-facing docs change here, run `just website`, inspect the
45
+ corresponding website changes, and update them as needed. If the change here is committed,
46
+ commit the corresponding website update in that repository as well; preserve unrelated work in
47
+ either working copy.
53
48
  - Active internal docs use ordinary technical language too. Introduce a project-specific term
54
49
  only when it names a real type, field, or enduring rule, define it at first use, and prefer
55
50
  describing concrete inputs and effects.
@@ -76,13 +71,9 @@ compatibility code, migration code, or the like.
76
71
 
77
72
  # Testing
78
73
 
79
- - Run `./check.py` before finishing a code change. Docs-only edits under `docs/` do not require
80
- a test run.
81
- - Run `./check.py` for the default local Ruff, type-check, and test pass before finishing a
82
- code change.
83
- - For focused test runs, do not use plain `uv run pytest ...`; it can miss the repo's package
84
- path in this project layout. First run `uv sync --locked`, then invoke pytest through the repo
85
- virtualenv, for example `.venv/bin/python -m pytest tests/unit/test_jj_client.py`.
74
+ - Run `just check` for the default local Ruff, type-check, and test pass before finishing a code
75
+ change. Docs-only edits under `docs/` do not require a test run.
76
+ - Run focused tests with `just test`, for example `just test tests/unit/test_jj_client.py`.
86
77
  - Before adding, modifying, removing, or reviewing tests, fixtures, helpers, or property
87
78
  scenarios, read and follow
88
79
  [docs/internals/testing-philosophy.md](docs/internals/testing-philosophy.md). Add or retain
@@ -1,9 +1,10 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: jj-stack
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Stacked GitHub pull requests for Jujutsu
5
5
  Project-URL: Homepage, https://www.serpentine.com/software/jj-stack/
6
6
  Project-URL: Documentation, https://www.serpentine.com/software/jj-stack/
7
+ Project-URL: Changelog, https://github.com/bos/jj-stack/releases
7
8
  Project-URL: Repository, https://github.com/bos/jj-stack
8
9
  Project-URL: Issues, https://github.com/bos/jj-stack/issues
9
10
  License-Expression: Apache-2.0
@@ -20,6 +21,7 @@ Classifier: Topic :: Software Development :: Version Control
20
21
  Classifier: Topic :: Software Development :: Version Control :: Git
21
22
  Requires-Python: >=3.14
22
23
  Requires-Dist: httpxyz<0.32,>=0.31.0
24
+ Requires-Dist: markdown-it-py<5,>=4.0.0
23
25
  Requires-Dist: pydantic<3,>=2.13.3
24
26
  Requires-Dist: rich<16,>=15.0.0
25
27
  Description-Content-Type: text/markdown
@@ -35,31 +37,51 @@ matching PRs.
35
37
  ### Requirements
36
38
 
37
39
  - Python 3.14 or newer
38
- - `uv`
39
40
  - `jj` 0.44.0 or newer
40
41
  - GitHub authentication
41
42
 
42
43
  ### Install
43
44
 
44
- Install `jj-stack` from PyPI:
45
+ Install `jj-stack` from PyPI with `uv` in an isolated tool environment (recommended):
45
46
 
46
47
  ```bash
47
48
  uv tool install jj-stack
48
49
  ```
49
50
 
50
- To upgrade, rerun that command with `--force`. If the command is not on your shell `PATH`, run
51
- `uv tool update-shell`.
51
+ `pipx` provides another isolated installation:
52
52
 
53
- For tab completion, add the output of `jj-stack completion` to your shell startup file:
53
+ ```bash
54
+ pipx install jj-stack
55
+ ```
56
+
57
+ You can also use `pip` inside an activated virtual environment:
54
58
 
55
59
  ```bash
56
- eval "$(jj-stack completion zsh)"
60
+ python -m pip install jj-stack
57
61
  ```
58
62
 
59
- `bash` and `fish` work the same way.
63
+ To upgrade an installation made with `uv`, rerun its command with `--force`. If the command is
64
+ not on your shell `PATH`, run `uv tool update-shell`.
65
+
66
+ ### Invoke it as `jj stack`
67
+
68
+ Add a command alias to your user configuration with `jj config edit --user`:
69
+
70
+ ```toml
71
+ [aliases]
72
+ stack = ["util", "exec", "--", "jj-stack"]
73
+ ```
60
74
 
61
- To invoke it as `jj stack` and complete that alias too, see
62
- [Configuration](https://www.serpentine.com/software/jj-stack/reference/configuration/).
75
+ For tab completion of both `jj-stack` and `jj stack`, add the output of `jj-stack completion` to
76
+ your shell startup file:
77
+
78
+ ```bash
79
+ eval "$(jj-stack completion zsh --jj-alias stack)"
80
+ ```
81
+
82
+ `bash` and `fish` work the same way. See
83
+ [Configuration](https://www.serpentine.com/software/jj-stack/reference/configuration/) for more
84
+ setup options.
63
85
 
64
86
  ### Submit your first stack
65
87
 
@@ -126,7 +148,7 @@ merge queues, cleanup, and working with multiple stacks.
126
148
  - [Configuration](https://www.serpentine.com/software/jj-stack/reference/configuration/)
127
149
  - [Writing PR descriptions](https://www.serpentine.com/software/jj-stack/reference/descriptions/)
128
150
  - [Troubleshooting](https://www.serpentine.com/software/jj-stack/troubleshooting/)
129
- - [`jj-stack` and `gh stack`](https://www.serpentine.com/software/jj-stack/gh-stack/)
151
+ - [Tool comparison](https://www.serpentine.com/software/jj-stack/tool-comparison/)
130
152
  - [JSON output](https://www.serpentine.com/software/jj-stack/reference/json-output/)
131
153
  - [Automation and exit codes](https://www.serpentine.com/software/jj-stack/reference/automation/)
132
154
 
@@ -138,6 +160,12 @@ jj-stack <command> --help
138
160
  jj-stack help --all
139
161
  ```
140
162
 
163
+ ## Development
164
+
165
+ Contributor workflows live in the [`justfile`](justfile). With `uv`, `jj`, and `just` installed,
166
+ run `just` to list the setup, formatting, focused test, verification, documentation, and release
167
+ recipes.
168
+
141
169
  ## Coding agent integration
142
170
 
143
171
  Install the bundled skill to teach coding agents to work with local `jj` stacks and refresh their
@@ -9,31 +9,51 @@ matching PRs.
9
9
  ### Requirements
10
10
 
11
11
  - Python 3.14 or newer
12
- - `uv`
13
12
  - `jj` 0.44.0 or newer
14
13
  - GitHub authentication
15
14
 
16
15
  ### Install
17
16
 
18
- Install `jj-stack` from PyPI:
17
+ Install `jj-stack` from PyPI with `uv` in an isolated tool environment (recommended):
19
18
 
20
19
  ```bash
21
20
  uv tool install jj-stack
22
21
  ```
23
22
 
24
- To upgrade, rerun that command with `--force`. If the command is not on your shell `PATH`, run
25
- `uv tool update-shell`.
23
+ `pipx` provides another isolated installation:
26
24
 
27
- For tab completion, add the output of `jj-stack completion` to your shell startup file:
25
+ ```bash
26
+ pipx install jj-stack
27
+ ```
28
+
29
+ You can also use `pip` inside an activated virtual environment:
28
30
 
29
31
  ```bash
30
- eval "$(jj-stack completion zsh)"
32
+ python -m pip install jj-stack
31
33
  ```
32
34
 
33
- `bash` and `fish` work the same way.
35
+ To upgrade an installation made with `uv`, rerun its command with `--force`. If the command is
36
+ not on your shell `PATH`, run `uv tool update-shell`.
37
+
38
+ ### Invoke it as `jj stack`
39
+
40
+ Add a command alias to your user configuration with `jj config edit --user`:
41
+
42
+ ```toml
43
+ [aliases]
44
+ stack = ["util", "exec", "--", "jj-stack"]
45
+ ```
34
46
 
35
- To invoke it as `jj stack` and complete that alias too, see
36
- [Configuration](https://www.serpentine.com/software/jj-stack/reference/configuration/).
47
+ For tab completion of both `jj-stack` and `jj stack`, add the output of `jj-stack completion` to
48
+ your shell startup file:
49
+
50
+ ```bash
51
+ eval "$(jj-stack completion zsh --jj-alias stack)"
52
+ ```
53
+
54
+ `bash` and `fish` work the same way. See
55
+ [Configuration](https://www.serpentine.com/software/jj-stack/reference/configuration/) for more
56
+ setup options.
37
57
 
38
58
  ### Submit your first stack
39
59
 
@@ -100,7 +120,7 @@ merge queues, cleanup, and working with multiple stacks.
100
120
  - [Configuration](https://www.serpentine.com/software/jj-stack/reference/configuration/)
101
121
  - [Writing PR descriptions](https://www.serpentine.com/software/jj-stack/reference/descriptions/)
102
122
  - [Troubleshooting](https://www.serpentine.com/software/jj-stack/troubleshooting/)
103
- - [`jj-stack` and `gh stack`](https://www.serpentine.com/software/jj-stack/gh-stack/)
123
+ - [Tool comparison](https://www.serpentine.com/software/jj-stack/tool-comparison/)
104
124
  - [JSON output](https://www.serpentine.com/software/jj-stack/reference/json-output/)
105
125
  - [Automation and exit codes](https://www.serpentine.com/software/jj-stack/reference/automation/)
106
126
 
@@ -112,6 +132,12 @@ jj-stack <command> --help
112
132
  jj-stack help --all
113
133
  ```
114
134
 
135
+ ## Development
136
+
137
+ Contributor workflows live in the [`justfile`](justfile). With `uv`, `jj`, and `just` installed,
138
+ run `just` to list the setup, formatting, focused test, verification, documentation, and release
139
+ recipes.
140
+
115
141
  ## Coding agent integration
116
142
 
117
143
  Install the bundled skill to teach coding agents to work with local `jj` stacks and refresh their
@@ -18,6 +18,7 @@ VENV_PYTHON = (
18
18
  REPO_ROOT / ".venv" / (Path("Scripts/python.exe") if os.name == "nt" else Path("bin/python"))
19
19
  )
20
20
  PytestJobs = int | Literal["auto"]
21
+ _PYREFLY_TARGETS = ("src", "tests", "tools", "check.py")
21
22
  _FRAGILE_TEST_OUTPUT_PATTERNS: tuple[tuple[str, re.Pattern[str]], ...] = (
22
23
  (
23
24
  "use output assertion helpers instead of exact captured output equality",
@@ -77,10 +78,17 @@ def _build_checks(
77
78
  return (
78
79
  ("ruff", ("-m", "ruff", "check")),
79
80
  ("ruff-format", ("-m", "ruff", "format", "--check")),
80
- ("pyrefly", ("-m", "pyrefly", "check")),
81
+ ("pyrefly", ("-m", "pyrefly", "check", *_PYREFLY_TARGETS)),
81
82
  (
82
83
  "pyrefly-windows",
83
- ("-m", "pyrefly", "check", "--python-platform", "win32"),
84
+ (
85
+ "-m",
86
+ "pyrefly",
87
+ "check",
88
+ "--python-platform",
89
+ "win32",
90
+ *_PYREFLY_TARGETS,
91
+ ),
84
92
  ),
85
93
  ("pytest", pytest_command),
86
94
  )
@@ -49,6 +49,7 @@ governed = [
49
49
  "src/jj_stack/commands/sync.py",
50
50
  "src/jj_stack/commands/sync_apply.py",
51
51
  "src/jj_stack/models/tracking.py",
52
+ "src/jj_stack/state/migrations.py",
52
53
  "src/jj_stack/state/store.py",
53
54
  "src/jj_stack/stack/trunk_evidence.py",
54
55
  "src/jj_stack/stack/convergence.py",
@@ -23,12 +23,13 @@ web navigation and presentation.
23
23
  ## Reference and troubleshooting
24
24
 
25
25
  - [Command reference](reference/commands.md)
26
+ - [Bookmarks and stack selection](reference/bookmarks-and-selection.md)
26
27
  - [Configuration](reference/configuration.md)
27
28
  - [Pull request descriptions](reference/descriptions.md)
28
29
  - [Automation and agents](reference/automation.md)
29
30
  - [JSON output](reference/json-output.md)
30
31
  - [Troubleshooting](troubleshooting.md)
31
- - [`jj-stack` and `gh stack`](gh-stack.md)
32
+ - [Compare `jj-stack` with other tools](tool-comparison.md)
32
33
 
33
34
  The built-in help is the exact flag and alias reference:
34
35
 
@@ -30,9 +30,8 @@ Choose any pull request in your stack:
30
30
  jj-stack checkout --pull-request <pr>
31
31
  ```
32
32
 
33
- `checkout` follows the selected pull request down to the bottom of its stack, fetches those
34
- commits, records which local change belongs to each pull request, and runs `jj edit` on the
35
- selected pull request's change.
33
+ `checkout` follows that pull request down to the bottom of its stack, fetches those commits,
34
+ records which local change belongs to each pull request, and runs `jj edit` on its change.
36
35
 
37
36
  To start a new change on top instead of editing that change directly, run:
38
37
 
@@ -54,4 +53,5 @@ jj-stack submit <head-change-id>
54
53
  ```
55
54
 
56
55
  `relink` is a repair command for this specific mismatch. It verifies that your pull request's
57
- branch belongs to your selected change; it cannot attach an unrelated pull request to new work.
56
+ branch belongs to the local change you chose; it cannot attach an unrelated pull request to new
57
+ work.
@@ -52,9 +52,9 @@ After GitHub merges some or all of your pull requests, `sync` fetches trunk, rem
52
52
  changes from your local history if needed, rebases your remaining changes, updates your remaining
53
53
  pull requests, and removes your PR branches when they are no longer needed.
54
54
 
55
- If no selected pull request has merged and GitHub has not rebased the stack, `sync` reports that
56
- there are no merged changes and leaves the pull requests unchanged. Run `submit` explicitly when
57
- you want to publish local changes.
55
+ If none of the pull requests in your stack has merged and GitHub has not rebased the stack,
56
+ `sync` reports that there are no merged changes and leaves the pull requests unchanged. Run
57
+ `submit` explicitly when you want to publish local changes.
58
58
 
59
59
  What does “removes the merged changes from your local history” mean? If GitHub uses a merge
60
60
  commit or rebase merge for your pull requests, it preserves their `jj` change IDs, and
@@ -69,16 +69,16 @@ not need to run another cleanup command.
69
69
 
70
70
  ### Merge queues
71
71
 
72
- When `merge` uses a merge queue, it returns successfully once GitHub accepts your selected pull
73
- requests into the queue. This does not mean trunk has changed. Wait until GitHub reports that
74
- your stack has merged. Then run `sync` with the head of your stack:
72
+ When `merge` uses a merge queue, it returns successfully once GitHub accepts the pull requests
73
+ you asked it to merge. This does not mean trunk has changed. Wait until GitHub reports that your
74
+ stack has merged. Then run `sync` with the head of your stack:
75
75
 
76
76
  ```console
77
77
  jj-stack sync <head-change-id>
78
78
  ```
79
79
 
80
- If you run either command while one of your selected pull requests is queued, `submit` and `sync`
81
- leave your stack unchanged.
80
+ If you run either command while one of those pull requests is queued, `submit` and `sync` leave
81
+ your stack unchanged.
82
82
 
83
83
  ### Merges outside jj-stack
84
84
 
@@ -113,9 +113,9 @@ to it. It also removes branches, comments, and saved pull-request links for merg
113
113
  local changes are gone. If one stack cannot be updated, jj-stack explains why and continues with
114
114
  independent stacks.
115
115
 
116
- Like selected `sync`, `sync --all` does not rebase a stack merely because trunk advanced. A
117
- selected `sync` also recognizes a completed native GitHub stack rebase because GitHub moved every
118
- PR branch and the rewritten contents can be verified.
116
+ `sync --all` and `sync <head-change-id>` do not rebase a stack merely because trunk advanced.
117
+ `sync <head-change-id>` also recognizes a completed native GitHub stack rebase because GitHub
118
+ moved every PR branch and the rewritten contents can be verified.
119
119
 
120
120
  ## If `merge` fails after GitHub merges your pull requests
121
121
 
@@ -11,11 +11,17 @@ locally; reviewers work with native stacked pull requests on GitHub.
11
11
 
12
12
  ## Read the stack map
13
13
 
14
- GitHub shows the ordered stack and each pull request's position. Start at the bottom, which is
15
- closest to the final base branch, and move upward. Each pull request's **Files changed** view is
16
- the diff for that layer, not the cumulative diff from the final base. Review and approve each
14
+ GitHub shows the ordered stack and each pull request's position. Start at the bottom, where the
15
+ stack branches from its base branch, and move upward. Each pull request's **Files changed** view
16
+ is the diff for that layer, not the cumulative diff from the base branch. Review and approve each
17
17
  layer independently, while reading a higher layer with its dependencies in mind.
18
18
 
19
+ From a checkout that tracks the stack, you can print the same order before opening GitHub:
20
+
21
+ ```console
22
+ jj-stack view --pull-request <pr>
23
+ ```
24
+
19
25
  ## Review and merge in order
20
26
 
21
27
  Comments, requested changes, approvals, CODEOWNERS, and required checks remain per pull request.
@@ -78,6 +78,12 @@ previously approved or asked for changes (i.e. revoking the approved state of yo
78
78
  jj-stack submit --re-request
79
79
  ```
80
80
 
81
+ ## PR history
82
+
83
+ To make it easier for a reader to understand how a pull request has changed over time, when you
84
+ run `submit` to update a PR that you have submitted before, `jj-stack` will keep a comment up to
85
+ date on the PR that shows its most recent versions, with a link to the diff for each update.
86
+
81
87
  ## What the `submit` command changes
82
88
 
83
89
  | Surface | Effect |
@@ -86,6 +92,7 @@ jj-stack submit --re-request
86
92
  | PR branches | Created or updated |
87
93
  | Pull requests | Created or updated |
88
94
  | Pull request order | Updated to match the local change order |
95
+ | Pull request comments | Revision history maintained |
89
96
  | Other local stacks | Not changed |
90
97
 
91
98
  With `jj`, you can easily move your changes between existing stacks. However, GitHub allows each